setState does not fire dynamically (React) - javascript

CodeSandbox
function disabledRow on click does not send changed data to child component.
I don't see any error in the code. Can't figure out how to display data in child component.
const UsersPage = () => {
const [dataState, setDataState] = useState<DataType[]>(dataInitial);
const [idState, setIdState] = useState<number[]>();
const disabledRow = () => {
if (idState) {
dataInitial.forEach((item) => {
if (idState.some((id) => id === item.id)) {
item.activeStatus = false;
item.date = <StopOutlined />;
item.status = "Not active";
}
});
return setDataState(dataState);
}
};
const idRow = (id: number[]) => {
return setIdState(id);
};
console.log("Hello", dataState);
return (
<div>
<div className={"wrapper"}>
<Button onClick={disabledRow}>
<StopOutlined /> Deactivate
</Button>
</div>
<UsersTable data={dataState} idRow={idRow} />
</div>
);
};

Related

How to avoid prop drilling ? / How to use useContext?

I'm working on a React Notes Application and my App.js contains all the necessary functions props which are passed down to several components.
As a result I'm doing prop drilling a lot where I'm passing down around 10-20 props/functions in the components where it isn't needed.
I tried using useContext Hook but I guess it doesn't work with callback functions in the value parameter.
App.js
const App = () => {
const [ notes, setNotes ] = useState([]);
const [ category, setCategory ] = useState(['Notes']);
const [ searchText, setSearchText ] = useState('');
const [ alert, setAlert ] = useState({
show:false,
msg:'',
type:''
});
const [isEditing, setIsEditing] = useState(false);
const [editId, setEditId] = useState(null);
useEffect(()=>{
keepTheme();
})
// retreive saved notes
useEffect(()=>{
const savedNotes = JSON.parse(localStorage.getItem('react-notes-data'));
if (savedNotes) {
setNotes(savedNotes)
}
}, []);
// save notes to local storage
useEffect(() => {
localStorage.setItem('react-notes-data', JSON.stringify(notes))
setNotesCopy([...notes]);
}, [notes]);
// save button will add new note
const addNote = (text) => {
const date = new Date();
const newNote = {
id: nanoid(),
text: text,
date: date.toLocaleDateString(),
category: category,
}
const newNotes = [...notes, newNote]
setNotes(newNotes);
}
const deleteNote = (id) => {
showAlert(true, 'Note deleted', 'warning');
const newNotes = notes.filter(note => note.id !== id);
setNotes(newNotes);
}
// hardcoded values for categories
const allCategories = ['Notes', 'Misc', 'Todo', 'Lecture Notes', 'Recipe'];
// copy notes for filtering through
const [notesCopy, setNotesCopy] = useState([...notes]);
const handleSidebar = (category) => {
setNotesCopy(category==='Notes'?[...notes]:
notes.filter(note=>note.category===category));
}
// function to call alert
const showAlert = (show=false, msg='', type='') => {
setAlert({show, msg, type});
}
return (
<div>
<div className="container">
<Sidebar
allCategories={allCategories}
handleSidebar={handleSidebar}
notesCopy={notesCopy}
key={notes.id}
/>
<Header notes={notes} alert={alert} removeAlert={showAlert} />
<Search handleSearchNote={setSearchText} />
<NotesList
notesCopy={notesCopy.filter(note=>
note.text.toLowerCase().includes(searchText) ||
note.category.toString().toLowerCase().includes(searchText)
)}
handleAddNote={addNote}
deleteNote={deleteNote}
category={category}
setCategory={setCategory}
allCategories={allCategories}
showAlert={showAlert}
notes={notes}
setNotes={setNotes}
editId={editId}
setEditId={setEditId}
isEditing={isEditing}
setIsEditing={setIsEditing}
/>
</div>
</div>
)
}
NotesList.js
const NotesList = (
{ notesCopy, handleAddNote, deleteNote, category, setCategory, showHideClassName, allCategories, showAlert, isEditing, setIsEditing, notes, setNotes, editId, setEditId }
) => {
const [ noteText, setNoteText ] = useState('');
const textareaRef = useRef();
// function to set edit notes
const editItem = (id) => {
const specificItem = notes.find(note=>note.id === id);
setNoteText(specificItem.text);
setIsEditing(true);
setEditId(id);
textareaRef.current.focus();
}
return (
<div key={allCategories} className="notes-list">
{notesCopy.map(note => {
return (
<Note
key={note.id}
{...note}
deleteNote={deleteNote}
category={note.category}
isEditing={isEditing}
editId={editId}
editItem={editItem}
/>)
})}
<AddNote
handleAddNote={handleAddNote}
category={category}
setCategory={setCategory}
showHideClassName={showHideClassName}
allCategories={allCategories}
showAlert={showAlert}
isEditing={isEditing}
setIsEditing={setIsEditing}
notes={notes}
setNotes={setNotes}
editId={editId}
setEditId={setEditId}
noteText={noteText}
setNoteText={setNoteText}
textareaRef={textareaRef}
/>
</div>
)
}
AddNote.js
const AddNote = ({ notes, setNotes, handleAddNote, category, setCategory, showHideClassName, allCategories, showAlert, isEditing, setIsEditing, editId, setEditId, noteText, setNoteText, textareaRef }) => {
const [ show, setShow ] = useState(false);
const [ modalText, setModalText ] = useState('');
const charCount = 200;
const handleChange = (event) => {
if (charCount - event.target.value.length >= 0) {
setNoteText(event.target.value);
}
}
const handleSaveClick = () => {
if (noteText.trim().length === 0) {
setModalText('Text cannot be blank!');
setShow(true);
}
if (category === '') {
setModalText('Please select a label');
setShow(true);
}
if (noteText.trim().length > 0 && category!=='') {
showAlert(true, 'Note added', 'success');
handleAddNote(noteText);
setNoteText('');
setShow(false);
}
if (noteText.trim().length > 0 && category!=='' && isEditing) {
setNotes(notes.map(note=>{
if (note.id === editId) {
return ({...note, text:noteText, category:category})
}
return note
}));
setEditId(null);
setIsEditing(false);
showAlert(true, 'Note Changed', 'success');
}
}
const handleCategory = ( event ) => {
let { value } = event.target;
setCategory(value);
}
showHideClassName = show ? "modal display-block" : "modal display-none";
return (
<div className="note new">
<textarea
cols="10"
rows="8"
className='placeholder-dark'
placeholder="Type to add a note.."
onChange={handleChange}
value={noteText}
autoFocus
ref={textareaRef}
>
</textarea>
<div className="note-footer">
<small
className='remaining'
style={{color:(charCount - noteText.length == 0) && '#c60000'}}>
{charCount - noteText.length} remaining</small>
<div className='select'>
<select
name={category}
className="select"
onChange={(e)=>handleCategory(e)}
required
title='Select a label for your note'
defaultValue="Notes"
>
<option value="Notes" disabled selected>Categories</option>
{allCategories.map(item => {
return <option key={item} value={item}>{item}</option>
})}
</select>
</div>
<button className='save' onClick={handleSaveClick} title='Save note'>
<h4>{isEditing ? 'Edit':'Save'}</h4>
</button>
</div>
{/* Modal */}
<main>
<div className={showHideClassName}>
<section className="modal-main">
<p className='modal-text'>{modalText}</p>
<button type="button" className='modal-close-btn'
onClick={()=>setShow(false)}><p>Close</p>
</button>
</section>
</div>
</main>
</div>
)
}
I want the functions passed from App.js to NotesList.js to be in AddNote.js without them being passed in NotesList.js basically minimizing the props destructuring in NotesList.js
Context API does work with function. What you need to do is pass your function to Provider inside value :
<MyContext.Provider value={{notes: notesData, handler: myFunction}} >
For example:
// notes-context.js
import React, { useContext, createContext } from 'react';
const Context = createContext({});
export const NotesProvider = ({children}) => {
const [notes, setNote] = useState([]);
const addNote = setNote(...); // your logic
const removeNote = setNote(...); // your logic
return (
<Context.Provider value={{notes, addNote, removeNote}}>
{children}
</Context.Provider>
)
}
export const useNotes = () => useContext(Context);
Add Provider to your App.js like so:
// App.js
import NoteProvider from './notes-context';
export default App = () => {
return (
<NoteProvider>
<div>... Your App</div>
</NoteProvider>
)
}
Then call UseNote in your NoteList.js to use the function:
// NoteList.js
import {useNotes} from './note-context.js';
export const NoteList = () => {
const {notes, addNotes, removeNotes} = useNotes();
// do your stuff. You can now use functions addNotes and removeNotes without passing them down the props
}

setState hook in Promise.all only updates the last element of the component state

Here is the codepen and the code below.
The state of my component is an array of todos that is created and updated with a useState hook. Each todo can be edited and saved with its own Save button that calls a saveTodo async function.
I'm trying to implement a Save All button which would the call the saveTodo function for each todo in a Promise.all - see handleOnSaveAllClicked below
Right now only the last todo is updated. Any clue to update them all ?
Thank you.
async function stall(stallTime = 3000) {
await new Promise(resolve => setTimeout(resolve, stallTime));
}
const Todo = ({ todo, onFormChanged }) => {
const onChange = (key) => {
return (e) => onFormChanged(todo.id, { [key]: e.target.value });
};
return (
<div>
<label>
<p>Name</p>
</label>
<input type="text" value={todo.name} onChange={onChange("name")} />
</div>
);
};
const App = () => {
const initDate = new Date()
const initialTodos = [
{ id: 1, name: "Todo 1", time: initDate},
{ id: 2, name: "Todo 2", time: initDate }
];
const [todos, setTodos] = React.useState(initialTodos);
const saveTodo = async (todo) => {
//simulate async http call
await stall(1000)
const newTodo = { ...todo, ...{ time: new Date() } };
setTodos(todos.map((t) => (t.id === newTodo.id ? newTodo : t)));
};
const handleOnSaveAllClicked = async () => {
await Promise.all(todos.map(t => saveTodo(t)))
}
const handleOnSaveClicked = async (id) => {
const todo = todos.find((t) => t.id === id);
await saveTodo(todo)
};
const handleFormChange = (id, data) => {
const todo = todos.find((t) => t.id === id);
const newTodo = { ...todo, ...data };
setTodos(todos.map((t) => (t.id === id ? newTodo : t)));
};
return (
<div>
<button type="button" onClick={(e) => {
e.preventDefault();
handleOnSaveAllClicked();
}}
>Save All</button>
{todos.map((t) => {
return (
<div>
<form onSubmit={(e) => e.preventDefault()}>
<p>{t.name} lasted saved on {t.time.toLocaleString()}</p>
<button
type="button"
onClick={(e) => {
e.preventDefault();
handleOnSaveClicked(t.id);
}}
>
Save
</button>
<Todo todo={t} key={t.id} onFormChanged={handleFormChange} />
</form>
</div>
);
})}
</div>
);
};
ReactDOM.render(<App />, document.getElementById("root"));
The problem is that you're using the todos that existed when the function was created, not the most recent todos. So you end up overwriting any changes that have been made in the meantime. To use the most recent one, use the function version of setTodos:
setTodos(prev => prev.map((t) => (t.id === newTodo.id ? newTodo : t)));

React, handle modal from component

How can I catch the click on some buttom from a modal, to return true or false to the component that is calling the modal?
handleSubmitSaveConfigurations = async (row) => {
const { scadaValidation } = this.props;
const result = await scadaValidation(11);
if (result.statusCode !== 200) {
// Opens the modal to ask if you really want to save
this.setState({openSimpleModal: true});
this.setState({contentSimpleModal: this.warningModal()});
// Here I have to catch if the modal click yes or no.
// In case yes, do nothing and continue with the code
// But in case "no" returns false and stops
}
// If result.statusCode === 200 returns true
return true;
}
warningModal = () => (
<div>
Do you want to save?
<Button id="btnClose" onClick={() => this.handleModalClickClose()}>No</Button>
<Button id="btnSave" onClick={() => this.handleModalClickClose()}>Yes</Button>
</div>
);
handleModalClickClose = () => this.setState({ openSimpleModal: false });
You could pass a handler to be executed inside your modal.
const Modal = ({ callback }) =>{
const handleClick = arg => callback(arg)
return(
<div>
<button onClick={() => handleClick('button1')}>A</button>
<button onClick={() => handleClick('button2')}> B</button>
</div>
)
}
And expect to receive this value inside the component which is calling Modal
const TheOneWhoCalls = () =>{
const onModalClick = arg => console.log(arg)
return <Modal callback={onModalClick} />
}
You can create a function on the parent component, and inside the modal, u only use it.
https://reactjs.org/docs/lifting-state-up.html#lifting-state-up
Parent:
constructor () {
this.state: {test: false}
}
setStateTest (value) {
this.setState(value)
}
render () {
return <modal handlerSetParentStateTest = {setStateTest}></modal>
}
Modal:
// this will set the parent state
this.props.handlerSetParentStateTest(true);
I want to share my solution, for sure I will need it in the future. it the implementation of #Dupocas
const Modal = ({ callback }) => {
const handleClick = arg => callback(arg)
return (
<div>
Wanna save?
<Button id="btnCloseModal" onClick={() => handleClick(0)}>No</Button>
<Button id="btnGuardarConfirm" onClick={() => handleClick(1)}>Sí</Button>
</div>)
};
class TableDisplayReportRecord extends Component<Props, State> {
constructor {...}
handleValidate = async (row) => {
const { scadaValidation } = this.props;
const verify = await scadaValidation();
if (verify.statusCode !== 200) {
this.setState({openSimpleModal: true});
const onModalClick = arg => {
this.setState({openSimpleModal: false});
//do nothing
if (arg === 0) return false;
//if user selected "Yes", call the function that I need
else this.handleSubmitSave(row);
};
this.setState({contentSimpleModal:
<Modal
callback={onModalClick}
/>
})
}
}
handleSubmitSave = async (row) => {...}
...
}

React: Access properties of dynamically created elements by refs

I have a dynamically created list of 5 input elements. When I now click on a "plus" icon element (from IonicIcons) in React, I want the first of those input fields to be focused.
My input List:
if (actualState.showInputField === true) {
inputField = (
<div>
{
actualState.inputFields.map((val,index) => (
<ListElemErrorBoundary key={index}>
<InputElement key={index} elemValue = {val} name={"input" + index} onChangeListener={(event) => handleDoublettenIDs(event,index)} />
</ListElemErrorBoundary>
)
)
}
{actualState.errorMessage!= '' ? <Alert color="danger" >{actualState.errorMessage}</Alert> : null}
{actualState.successMessage !='' ? <Alert color="success" >{actualState.successMessage}</Alert> : null}
<br />
<p><button onClick = { () => {
handleInputs(props.anzeigeID);
vanishMessage();
}
}>absenden</button></p>
</div>
)
}
return inputField;
}
My Icon:
const checkIcon = () => {
let showIcon = null;
if (actualState.showInputField === false) {
showIcon = (
<IoIosAddCircleOutline ref={toggleSignRef} onClick = {toggleInput}
/>
)
} else {
showIcon = (
<IoIosRemoveCircleOutline onClick = {toggleInput}
/>
)
}
return showIcon;
}
I probably should place my ref on the list items, however, I guess that for every new list element, this ref gets "overwritten" because I have only one ref. Should I do something like a input key query, to find out which list key input element this is, and if it is the first input key index, I execute a focus on that input element?
And how then can I retrieve the first input element inside the method toggleInput() where I set the showInputField value? Is it somehow possible to ask for the props.key of that input element's reference?
This component is a functional component and I use useRef only...
My Component:
import React, {useState, useRef, useEffect} from "react";
import { IoIosAddCircleOutline } from 'react-icons/io';
import { IoIosRemoveCircleOutline } from 'react-icons/io';
import InputElement from './inputElementDublette';
import fetch from 'isomorphic-unfetch';
import getConfig from 'next/config';
import ListElemErrorBoundary from './ListElemErrorBoundary';
import { Button, Alert } from 'reactstrap';
let url_link;
let port = 7766;
const { serverRuntimeConfig, publicRuntimeConfig } = getConfig();
const apiUrl = publicRuntimeConfig.apiUrl; //|| publicRuntimeConfig.apiUrl;
const server = publicRuntimeConfig.SERVERNAME;
let doublettenListe_link = `http://${server}:${port}/doubletten/`;
//functional component with state, with useState
const DubletteComponent = props => {
const toggleSignRef = useRef();
const [actualState, changeState] = useState({
showInputField: false,
dublettenIDs: [],
errorMessage: '',
successMessage: '',
inputFields: ['','','','',''],
visible : false,
});
const toggleInput = () => {
changeState({...actualState, showInputField: !actualState.showInputField});
}
const vanishMessage = ()=>{
window.setTimeout(() => {
changeState({
...actualState,
errorMessage:'',
successMessage: '',
});
},7000);
}
const handleDoublettenIDs = (event,index) => {
let idnumber = event.target.value;
let newInputFields = [...actualState.inputFields];
newInputFields.splice(index,1, idnumber);
//console.log("new:",newInputFields);
if (isNaN(idnumber)) {
changeState({...actualState, errorMessage: 'ID is not a number'})
} if (idnumber > 2147483647) {
changeState({...actualState, errorMessage: 'Number can not be bigger than 2147483647!'})
}
else {
changeState({...actualState, inputFields: newInputFields, errorMessage: '' });
}
}
const handleInputs = (anzeigeID) => {
if (process.browser && apiUrl==='dev') {
doublettenListe_link = `http://localhost:${port}/doubletten/`;
}
if (actualState.errorMessage=='') {
let array = actualState.inputFields;
let filtered = array.filter(function(el) {
return el != '';
});
const requestOptions = {
method: 'POST',
headers: {'Accept': 'application/json', 'Content-Type':'application/json'},
body: JSON.stringify({
id: anzeigeID,
dublettenIDs: filtered
})
};
//console.log("inputfields:",filtered);
// Note: I'm using arrow functions inside the `.fetch()` method.
// This makes it so you don't have to bind component functions like `setState`
// to the component.
//console.log("link:", doublettenListe_link);
fetch(doublettenListe_link , requestOptions)
.then((response) => {
//console.log("Resp:", response);
let tempArray = ['','','','',''];
changeState({...actualState, inputFields: tempArray});
//console.log(actualState);
changeState({...actualState, dublettenIDs: []});
changeState({...actualState, successMessage: `Doubletten-IDs wurden erfolgreich eingetragen!`});
return response;
}).catch((error) => {
changeState({...actualState, errorMessage: `Error beim Eintrage der Dubletten. Bitte prüfen, ob der Server läuft. Error: ${error.statusText}`});
});
}
}
const checkIcon = () => {
let showIcon = null;
if (actualState.showInputField === false) {
showIcon = (
<IoIosAddCircleOutline onClick = {toggleInput}
/>
)
} else {
showIcon = (
<IoIosRemoveCircleOutline onClick = {toggleInput}
/>
)
}
return showIcon;
}
const checkPrerequisites = () => {
//let errorMessage = '';
let inputField = null;
// if (actualState.errorMessage != '') {
// errorMessage = (
// <Alert color="danger">{actualState.errorMessage}</Alert>
// )
// }
//Outsourcing check for variable and return JSX elements on conditionals
if (actualState.showInputField === true) {
inputField = (
<div>
{
actualState.inputFields.map((val,index) => (
<ListElemErrorBoundary key={index}>
<InputElement key={index} elemValue = {val} name={"input" + index} onChangeListener={(event) => handleDoublettenIDs(event,index)} />
</ListElemErrorBoundary>
)
)
}
{actualState.errorMessage!= '' ? <Alert color="danger" >{actualState.errorMessage}</Alert> : null}
{actualState.successMessage !='' ? <Alert color="success" >{actualState.successMessage}</Alert> : null}
<br />
<p><button onClick = { () => {
handleInputs(props.anzeigeID);
vanishMessage();
}
}>absenden</button></p>
</div>
)
}
return inputField;
}
return (
<div >
{checkIcon()} Dubletten eintragen
{checkPrerequisites()}
</div>
)
}
export default DubletteComponent
My InputElement Component:
const inputElement = (props) => (
<p>
<input
ref={props.ref}
value ={props.elemValue}
name={props.name}
type="number"
max="2147483647"
placeholder="Doubletten-ID"
onChange={props.onChangeListener}>
</input>
</p>
)
export default inputElement
The issue is you can not pass ref from your parent component to child component. In new version of react you can achieve this by using forwardRef api. Use it like below if you are in react #16 version.
import React from 'react'
const inputElement = React.forwardRef(props) => (
<p>
<input
ref={props.ref}
value ={props.elemValue}
name={props.name}
type="number"
max="2147483647"
placeholder="Doubletten-ID"
onChange={props.onChangeListener}>
</input>
</p>
)
//To focus textinput
this.inputref.focus();
Happy coding :)

Rendering One Instance of Component in React

I am trying to create an application that allows users to add patient records that contain name, phone and diagnosis. It gives them the ability to add new patients, edit current patients or entirely delete them.
I am rendering the name, phone, diagnosis, the edit-diganosis button and the EditDiagnosis component. The EditDiagnosis component renders a form in which the input fields are loaded already with the values entered by the user so that they can edit it.
The problem is that if I have more than 2 patient records and I click on the edit-diganosis button on the second record, it loads two instances of the EditDiagnosis component, one under the second record and that is intended and one under the first record and that is not what I want. I only want when I click on the edit-diagnosis button of a certain record, it only opens the form to edit this record, not all records.
I know I am doing something wrong but I cannot figure out how to associate each button with its own record.
The components I need help with are: PatientDiagnosis and EditDiagnosis
import React from 'react';
import Header from './Header';
import PatientDiagnosis from './PatientDiagnosis';
import AddPatient from './AddPatient';
import DiagnosisForm from './DiagnosisForm';
import EditDiagnosis from './EditDiagnosis';
export default class App extends React.Component {
state = {
patientsList: [],
inEditMode: false,
allowDelete: false
}
componentDidMount() {
try {
const data = localStorage.getItem('patientsList');
const parsedData = JSON.parse(data);
if (parsedData) {
this.setState(() => ({ patientsList: parsedData }));
}
} catch (e) {
}
}
componentDidUpdate(undefined, prevState) {
if (prevState.patientsList.length !== this.state.patientsList.length) {
const data = JSON.stringify(this.state.patientsList);
localStorage.setItem('patientsList', data);
}
}
addDiagnose = (patient) => {
if(patient.name && patient.phone && patient.diagnosis) {
this.setState((prevState) => ({ patientsList: prevState.patientsList.concat(patient)}));
}
else {
return 'Please fill out all the fields to continue.';
}
}
editDiagnose = (patient, id) => {
if (!patient.name || !patient.phone || !patient.diagnosis) {
return "Please fill out all the fields to continue.";
}
this.setState(prevState => {
prevState.patientsList[id] = patient;
return {
patientsList: prevState.patientsList,
inEditMode: !this.state.inEditMode
}
}
)
}
toggleEdit = (id) => {
console.log(id);
this.setState(() => ({inEditMode: !this.state.inEditMode}))
}
deleteDiagnose = (patientToDelete) => {
console.log(patientToDelete);
this.setState(
(prevState) => {
prevState.patientsList.map(patient => console.log(patient));
return {patientsList: prevState.patientsList.filter(patient => patientToDelete !==patient)};
}
)
}
render() {
return (
<div className="container">
<Header />
<PatientDiagnosis
patientsList={this.state.patientsList}
toggleEdit={this.toggleEdit}
inEditMode={this.state.inEditMode}
deleteDiagnose={this.deleteDiagnose}
editDiagnose={this.editDiagnose} />
<AddPatient addDiagnose={this.addDiagnose} />
</div>
)
}
}
const PatientDiagnosis = ({patientsList, deleteDiagnose, editDiagnose, inEditMode, toggleEdit}) => (
<div>
{patientsList.map((patient, index) => {
console.log(inEditMode);
return (
<div key={index}>
<h1>{patient.name}</h1>
<h1>{patient.phone}</h1>
<h1>{patient.diagnosis}</h1>
<button onClick={e => {e.preventDefault(); toggleEdit(patient)}}>Edit Diagnosis</button>
{inEditMode && <EditDiagnosis id={index} patient={patient} editDiagnose={editDiagnose} deleteDiagnose={deleteDiagnose}/>}
</div>
)
})}
</div>
)
export default PatientDiagnosis;
export default class EditDiagnosis extends React.Component {
state = {
id: this.props.id,
name: this.props.patient.name,
phone: this.props.patient.phone,
diagnosis: this.props.patient.diagnosis,
error: undefined
}
editDiagnose = (e, id) => {
e.preventDefault();
id = this.state.id;
const name = this.state.name;
const phone = this.state.phone;
const diagnosis = this.state.diagnosis;
const patient = {name, phone, diagnosis}
const error = this.props.editDiagnose(patient, id);
this.setState(()=>({error}));
if (!error) {
e.target.elements.name.value = '';
e.target.elements.phone.value = '';
e.target.elements.diagnosis.value = '';
}
}
toggleEdit = (e) => {
e.preventDefault();
this.setState(() => ({allowEdit: !this.state.allowEdit}))
}
changeName = (e) => {
const name = e.target.value;
this.setState(() => ({name}))
}
changePhone = (e) => {
const phone = e.target.value;
this.setState(() => ({phone}))
}
changeDiagnosis = (e) => {
const diagnosis = e.target.value;
this.setState(() => ({diagnosis}))
}
render() {
return (
<div>
{this.state.error && <p className="alert alert-danger" role="alert">{this.state.error}</p>}
{
<form
className="add-option"
id="patient-form"
onSubmit={this.editDiagnose}>
<DiagnosisForm
changeName={this.changeName}
changePhone={this.changePhone}
changeDiagnosis={this.changeDiagnosis}
name={this.state.name}
phone={this.state.phone}
diagnosis={this.state.diagnosis}
editDiagnose={this.editDiagnose}/>
<button className="btn btn-success" type="submit">Save Changes</button>
<button
className="btn btn-danger"
onClick={
e => {
e.preventDefault();
console.log(this.props.deleteDiagnose);
this.props.deleteDiagnose(this.props.patient);
}
}>Delete Diagnosis</button>
</form>}
</div>
)
}
}
export default class AddPatient extends React.Component {
state = {
error: undefined,
addNewPatient: false
}
addNewPatient = (e) => {
e.preventDefault();
this.setState(() => ({addNewPatient: !this.state.addNewPatient}));
}
cancelForm = (e) => {
e.preventDefault();
this.setState(() => ({error: undefined, addNewPatient: !this.state.addNewPatient}));
}
handleAddOption = (e) => {
e.preventDefault();
const name = e.target.elements.name.value.trim().toLowerCase();
const phone = e.target.elements.phone.value.trim().toLowerCase();
const diagnosis = e.target.elements.diagnosis.value.trim().toLowerCase();
const patient = {name, phone, diagnosis};
const error = this.props.addDiagnose(patient);
// this.setState(()=>({error, patientId: this.state.patientId + 1}));
if(patient.name && patient.phone && patient.diagnosis) {
this.setState(()=>({addNewPatient: !this.state.addNewPatient}));
}
if (!error) {
e.target.elements.name.value = '';
e.target.elements.phone.value = '';
e.target.elements.diagnosis.value = '';
}
}
render() {
return (
<div className="add-patient">
{this.state.error && <p className="alert alert-danger" role="alert">{this.state.error}</p>}
{!this.state.addNewPatient && <button onClick={this.addNewPatient} className="btn btn-primary">Add A New Patient</button>}
{this.state.addNewPatient &&
<form
className="add-option"
id="patient-form"
onSubmit={this.handleAddOption}>
<DiagnosisForm handleAddOption={this.handleAddOption}/>
<button className="btn btn-primary patient-form__btn" type="submit">Save</button>
<button onClick={this.cancelForm} className="btn btn-warning">Cancel</button>
</form>
}
</div>
)
}
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.0/umd/react-dom.production.min.js"></script>

Categories

Resources