I'm trying to require the name and email in my form. I originally had <button> nested within a <Link> and figured out that the <button> worked by itself to allow the input to be required, but that when it's nested within the <Link> it doesn't require it. I then added the link to be within the submitSurvey function and took the <Link> away from the render. It still won't require the input.
Here is my NameEmailComponent.js:
import React, { useState } from "react";
import { NameInput } from "../inputs/NameInput";
import { EmailInput } from "../inputs/EmailInput";
import { useHistory } from "react-router-dom";
export const NameEmailComponent = (props) => {
const [surveyValues, setSurveyValues] = useState({});
const [inlineData, setInlineData] = useState({});
const [question, setQuestion] = useState({});
const history = useHistory();
console.log(props);
const triggerBackendUpdate = () => {
setSurveyValues({});
setQuestion({});
};
const handleSubmit = (event) => {
event.preventDefault();
event.persist();
setSurveyValues(surveyValues);
setQuestion(question);
triggerBackendUpdate();
};
const callback = (name, value) => {
console.log("Form Data: ", name, ": ", value);
inlineData[name] = value;
setInlineData(inlineData);
console.log(inlineData);
};
const handleChange = (event) => {
event.preventDefault();
this.setState({ value: event.target.value });
console.log("Name: ", event.target.value);
};
const submitSurvey = async () => {
try {
await fetch("/api/survey", {
method: "POST",
body: JSON.stringify(inlineData),
headers: {
"Content-Type": "application/json",
},
});
history.push({ pathname: "/survey" });
} catch (err) {
console.log(err);
}
};
const inputs = props.inputs
? props.inputs.filter((inputOption) => inputOption)
: [];
return (
<>
<div id="nameContainer" className="form-group">
<form onSubmit={handleSubmit}>
{inputs.map((data, index) => {
let inputKey = `input-${index}`;
return data.type === "text" ? (
<NameInput
className="form-control my-3"
triggerCallback={callback}
name={data.name}
type={data.type}
placeholder={data.placeholder}
required={true}
onChange={handleChange}
key={inputKey}
/>
) : (
<EmailInput
className="form-control mt-3"
triggerCallback={callback}
name={data.name}
type={data.type}
placeholder={data.placeholder}
required={true}
onChange={handleChange}
key={inputKey}
/>
);
})}
<div className="col-6 mx-auto text-center">
<div className="button">
<button
className="btn btn-primary mt-4 mb-2 mx-5"
type="submit"
onClick={submitSurvey}
>
Begin Survey
</button>
</div>
</div>
</form>
</div>
</>
);
};
Here is my NameInput.js:
import React from "react";
import { useInputChange } from "../Hooks/useInputChangeHook";
import { isTextInput } from "../validators";
export const NameInput = (props) => {
const inputType = isTextInput(props.type) ? props.type : "text";
const { handleChange } = useInputChange(
props.defaultValue,
props.triggerCallback,
inputType
);
const inputProps = {
className: props.className ? props.className : "form-control",
onChange: handleChange,
required: props.required,
question: props.question,
placeholder: props.placeholder,
type: inputType,
options: props.options,
name: props.name ? props.name : `${inputType}_${props.key}`,
};
return (
<>
<div id={props.name}>
<input
{...inputProps}
required={props.required}
value={props.value || ""}
/>
</div>
</>
);
};
Related
I am trying to test my understanding of React but hit a mental block. Would it be possible to create a unique key / id within my <FormInput> component rather than creating the unique ID inside the <MainUI> component once the newly created item is passed up into <MainUI>? I find that weird and definitely feel like there is a way better method of doing this.
const MainUI = props => {
const receiveNewItem = enteredNewItem => {
const newItem = {
...enteredNewItem,
id: Math.random().toString()
}
props.addNewItem(newItem)
}
console.log(props.data)
return(
<div>
<FormInput receiveNewItem={receiveNewItem}/>
{/* <MaxAmount data={props.data} /> */}
<DisplayItems data={props.data} key={props.data.id} />
</div>
)
}
export default MainUI;
import { useState } from 'react'
import Card from './Card'
const FormInput = props => {
const [userInput, setUserInput] = useState({
name: '',
amount: '',
date: ''
})
const nameInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, name: e.target.value}
})
}
const amountInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, amount: e.target.value}
})
}
const dateInputHandler = e => {
setUserInput( prevObj => {
return {...prevObj, date: e.target.value}
})
}
const submitHandler = e => {
e.preventDefault()
props.receiveNewItem(userInput)
setUserInput( prevObj => { return {...prevObj, name: ''}})
}
return (
<Card>
<form onSubmit={submitHandler}>
<input
type="text"
placeholder="Name Input"
value={userInput.name}
onChange={nameInputHandler} />
<input
type="number"
placeholder="Amount Input"
value={userInput.amount}
onChange={amountInputHandler} />
<input
type="date"
placeholder="Date Input"
value={userInput.date}
onChange={dateInputHandler} />
<button>Add Item</button>
</form>
</Card>
)
}
export default FormInput;
I'm creating a playlist and I want to show my "favorite tracks" with a different icon, like a heart filled, by default render a bordered heart. Basically the default code is working but when refresh the page, the icon filled is gone and render the default.
And if anyone has a tip, i'm new in react and dont know if I can have many "useStates" like that.
I forgot to mention, the app are using Redux-persist, so the info continues in the store after the page refresh. That is why I want show the icon filled based on info at the store
import React, { useState, useEffect } from "react";
import ReactDOMServer from "react-dom/server";
import axios from "axios";
import { useSelector, useDispatch } from "react-redux";
import { ListContainer, PlayerStyle, InfoBox } from "./style.jsx";
import FavoriteBorderIcon from "#material-ui/icons/FavoriteBorder";
import FavoriteIcon from "#material-ui/icons/Favorite";
import PlayCircleOutlineIcon from "#material-ui/icons/PlayCircleOutline";
import PauseCircleOutlineIcon from "#material-ui/icons/PauseCircleOutline";
import MusicPlayer from "../MusicPlayer/index";
const List = () => {
const [isLoading, setLoading] = useState(true);
const [valueList, setValueList] = useState(20);
const [search, setSearch] = useState("");
const [dataList, setDataList] = useState([]);
const [trackList, setTrackList] = useState([]);
const [bannerAlbum, setBannerAlbum] = useState("");
const [createdBy, setCreatedBy] = useState("");
const [isPlayed, setIsPlayed] = useState(false);
const [musicPlayed, setMusicPlayed] = useState("");
const [showTrackList, setShowTrackList] = useState(true);
const [showFavoriteList, setShowFavoriteList] = useState(false);
const [favoriteData, setFavoriteData] = useState([]);
const favoriteList = useSelector(
(state) => state.FavoriteListReducer.favorites
);
const dispatch = useDispatch();
let chartPlaylist = `https://api.deezer.com/playlist/1111141961?&limit=${valueList}`;
useEffect(() => {
axios.get(chartPlaylist).then((res) => {
// console.log(res.data, "album");
setDataList(res.data);
setTrackList(res.data.tracks.data);
setBannerAlbum(res.data.picture_medium);
setCreatedBy(res.data.creator.name);
// Ao terminar a requisição dos dados, mostra os componentes
setLoading(false);
});
}, [chartPlaylist]);
useEffect(() => {
axios.all(favoriteList.map((l) => axios.get(l))).then(
axios.spread(function (...res) {
// all requests are now complete
setFavoriteData(res);
})
);
if (!showTrackList && favoriteList.length === 0) {
setShowTrackList(true);
setShowFavoriteList(false);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [favoriteList]);
const handleInput = (e) => {
setSearch(e.target.value);
};
const handlePlayed = () => {
if (!isPlayed) {
setIsPlayed(true);
} else {
setIsPlayed(false);
}
};
const handleIconSwap = (e) => {
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
!isPlayed ? <PlayCircleOutlineIcon /> : <PauseCircleOutlineIcon />
);
};
const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteIcon style={{ color: "red" }} />
)
);
};
const Del_fav = (e) => {
dispatch({
type: "DELETE_FAV",
remove: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteBorderIcon fontSize={"inherit"} />
)
);
};
// eslint-disable-next-line no-array-constructor
const handleFav = (e) => {
favoriteList.includes(
`https://api.deezer.com/track/${e.currentTarget.getAttribute("value")}`
)
? Del_fav(e)
: Add_fav(e);
};
const toggleData = () => {
if (showTrackList && favoriteList.length > 0) {
setShowTrackList(false);
setShowFavoriteList(true);
}
if (!showTrackList) {
setShowTrackList(true);
setShowFavoriteList(false);
}
};
if (isLoading) {
return <div>Loading...</div>;
}
return (
<>
<button
onClick={() => {
if (valueList < 100) {
setValueList(valueList + 20);
}
}}
>
adicionar +20 musicas
</button>
<br />
<br />
<br />
<button
onClick={() => {
toggleData();
}}
>
Mostrar Favoritos
</button>
<InfoBox>
<input
type="text"
value={search}
onChange={(e) => setSearch(e.target.value)}
/>
<div className="content">
<img src={bannerAlbum} alt="" />
<div className="Info--desc">
<h1>{dataList.title}</h1>
<div>
<span>criado por: </span>
{createdBy}
</div>
</div>
</div>
</InfoBox>
<ListContainer>
<div className="headerList">
<div className="rank">#</div>
<div className="favorite--icon">
{/* <FavoriteBorderIcon fontSize={"inherit"} /> */}
</div>
<div className="title--music">FAIXA</div>
<div className="title--artist">ARTISTA</div>
<div className="title--album">ALBUM</div>
<div className="title--duration">D.</div>
</div>
<div className="bodyList">
{showTrackList &&
trackList.map((item, key) => {
return (
<>
<div
key={key}
onMouseEnter={handleIconSwap}
onMouseLeave={(e) => {
if (!isPlayed) {
e.currentTarget.firstElementChild.innerHTML = key + 1;
} else {
e.currentTarget.firstElementChild.innerHTML =
ReactDOMServer.renderToString(
<PauseCircleOutlineIcon />
);
}
}}
>
<div
className="rank"
onClick={() => setMusicPlayed(trackList[key].preview)}
>
{key + 1}
</div>
<div className="favorite--icon">
// Here that has to dynamically render
<span value={item.id} onClick={(e) => handleFav(e)}>
<Icon favIco={false} />
</span>
</div>
<div className="title--music">
<a target="_blank" rel="noreferrer" href={item.link}>
{item.title}
</a>
</div>
<div className="title--artist">{item.artist.name}</div>
<div className="title--album">{item.album.title}</div>
<div className="title--duration">
{item.duration / 60 < 10
? "0" +
(item.duration / 60)
.toFixed(2)
.toString()
.replace(".", ":")
: (item.duration / 60)
.toFixed(2)
.toString()
.replace(".", ":")}
</div>
</div>
</>
);
})}
</div>
</ListContainer>
</>
);
};
const Icon = (props) => {
switch (props.favIco) {
case true:
return <FavoriteIcon style={{ color: "red" }} />;
case false:
return <FavoriteBorderIcon fontSize={"inherit"} />;
default:
return <FavoriteBorderIcon fontSize={"inherit"} />;
}
};
export default List;
My Reducer store is working fine, just not render the heart filled on load the page, if I click at heart and remove the info from the store and click again the icon change to filled again.
const initialState = {
favorites: [],
};
const List = (state = initialState, action) => {
switch (action.type) {
case "ADD_FAV":
return { ...state, favorites: [...state.favorites, action.newId] };
case "DELETE_FAV":
let index = state.favorites.indexOf(action.remove);
if (index > -1) {
state.favorites.splice(index, 1);
}
return {
...state,
favorites: [...state.favorites],
};
default:
}
return state;
};
export default List;
Thank you all
I've seen in your comment above that you're currently using redux-persist to keep the store between reloads, so having access to the data is not the problem.
Looking your code I think the problem might be with the way you're rendering the icons.
If I understood correctly, that is done by the Add_fav function:
const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: `https://api.deezer.com/track/${e.currentTarget.getAttribute(
"value"
)}`,
});
e.currentTarget.firstElementChild.innerHTML = ReactDOMServer.renderToString(
favoriteList.includes(e.currentTarget.getAttribute("value")) ? (
""
) : (
<FavoriteIcon style={{ color: "red" }} />
)
);
};
But this function only runs when you add a new favorite - hence the absence of the icons after a reload, because this part of the code would not be ran at all.
My suggestion would be to change the icon rendering logic to the return JSX of the component, instead of inside the event handler function. Something like this:
<span value={item.id} onClick={(e) => handleFav(e)}>
{
favoriteList.includes(item.id)
? <FavoriteIcon style={{ color: "red" }} />
: <FavoriteBorderIcon fontSize={"inherit"} />
}
</span>
So figured out I was send to the store was a string and at the render logic was searching for a int number, then a edited the function add the method parseInt()
const Add_fav = (e) => {
dispatch({
type: "ADD_FAV",
newId: parseInt(e.currentTarget.getAttribute("value")),
});
};
and now works fine bacause the logic is searching for a Number Int.
<span value={item.id} onClick={(e) => handleFav(e)}>
{
favoriteList.includes(item.id)
? <FavoriteIcon style={{ color: "red" }} />
: <FavoriteBorderIcon fontSize={"inherit"} />
}
</span>
I have very simple ediable book-list. But when I press 'edit' and edit just one of two fields the other one behaves unexpectedly (it clears out even tho there was a value, or takes unexpected value from God knows where). It works correctly only if I edit both fields at once.
Here's my code:
import './App.css';
import React, { useState, useEffect } from 'react';
function App() {
const [books, setBooks] = useState([]);
const [book, setBook] = useState({
id: '',
title: '',
author: ''
});
const [alertMessage, setAlertMessage] = useState(false);
const [successMessage, setSuccessMessage] = useState(false);
const [editMode, setEditMode] = useState(null);
const [titleValue, setTitleValue] = useState('');
const [authorValue, setAuthorValue] = useState('');
useEffect(()=> {
const data = localStorage.getItem('books');
if(data) {
setBooks(JSON.parse(data))
}
}, [])
useEffect(()=> {
localStorage.setItem('books', JSON.stringify(books))
},)
function addBook (e) {
e.preventDefault();
if(!book.title && !book.author){
setAlertMessage(true)
setTimeout(()=>setAlertMessage(false), 3000)
} else {
let newBook = {
...book,
id: Math.floor(Math.random() * 100000000),
};
setBooks([newBook, ...books]);
setBook({
title: '',
author: ''
});
setSuccessMessage(true)
setTimeout(()=>setSuccessMessage(false), 1000);
}
}
function deleteBook(id){
setBooks(books.filter(book => book.id !== id))
}
function editBook(id) {
setEditMode(id);
}
function onChange(e) {
setBook({
...book,
[e.target.name]: e.target.value
})
}
function saveChanges (id) {
let newBook = [...books].map(book => {
if(book.id === id) {
book.title = titleValue;
book.author = authorValue
}
return book
});
setBook(newBook);
setEditMode(null)
}
return (
<div className='container'>
{alertMessage && <div className='alertMeaage'>Please, enter book author or its title</div>}
{successMessage && <div className='successMessage'>Book is successfully added!</div>}
<div className='BookForm'>
<h3>Add book</h3>
<input name='title' type='text' placeholder='Enter book title' value={book.title} onChange={onChange}/>
<input name='author' type='text' placeholder='Enter book author' value={book.author} onChange={onChange}/>
<button className='submitBtn' onClick={addBook}>Send</button>
</div>
<div>
<h4>Recently added books:</h4>
<div key={book.id}>{books.map(book => (
<div className='bookItem'>
{editMode !== book.id ? <><span className='titleAuthor'>Title: </span><i>«{book.title}» </i>
<span className='titleAuthor'>Author: </span> <i>{book.author}</i>
<button onClick={()=>deleteBook(book.id)} className='deleteBtn'>X</button>
<button onClick={()=>editBook(book.id)} className='editBtn'>Edit</button></>
:
<form className='form'>
<input name='title' type='text' defaultValue={book.title} onChange={(e)=> setTitleValue(e.target.value)}/>
<input name='author' type='text' defaultValue={book.author} onChange={(e)=> setAuthorValue(e.target.value)}/>
<button className='saveBtn' onClick={()=>saveChanges(book.id)}>Save</button>
</form>
}
</div>
))}
</div>
</div>
</div>
);
}
export default App;
Thanks a lot in advance!
When you edit new book, authorValue and titleValue still have previous values, so you must setAuthorValue and setTitleValue in editBook function. See below:
function editBook(book) {
setEditMode(book.id);
setTitleValue(book.title);
setAuthorValue(book.author);
}
And handle event:
<button onClick={() => editBook(book)} className="editBtn">
Edit
</button>
All code:
// import './App.css';
import React, { useState, useEffect } from "react";
function App() {
const [books, setBooks] = useState([]);
const [book, setBook] = useState({
id: "",
title: "",
author: ""
});
const [alertMessage, setAlertMessage] = useState(false);
const [successMessage, setSuccessMessage] = useState(false);
const [editMode, setEditMode] = useState(null);
const [titleValue, setTitleValue] = useState("");
const [authorValue, setAuthorValue] = useState("");
useEffect(() => {
const data = localStorage.getItem("books");
if (data) {
setBooks(JSON.parse(data));
}
}, []);
useEffect(() => {
localStorage.setItem("books", JSON.stringify(books));
});
function addBook(e) {
e.preventDefault();
if (!book.title && !book.author) {
setAlertMessage(true);
setTimeout(() => setAlertMessage(false), 3000);
} else {
let newBook = {
...book,
id: Math.floor(Math.random() * 100000000)
};
setBooks([newBook, ...books]);
setBook({
title: "",
author: ""
});
setSuccessMessage(true);
setTimeout(() => setSuccessMessage(false), 1000);
}
}
function deleteBook(id) {
setBooks(books.filter((book) => book.id !== id));
}
function editBook(book) {
setEditMode(book.id);
setTitleValue(book.title);
setAuthorValue(book.author);
}
function onChange(e) {
console.log(e.target.name, e.target.value);
setBook({
...book,
[e.target.name]: e.target.value
});
}
function saveChanges(id) {
let newBook = [...books].map((book) => {
if (book.id === id) {
book.title = titleValue;
book.author = authorValue;
}
return book;
});
setBook(newBook);
setEditMode(null);
}
return (
<div className="container">
{alertMessage && (
<div className="alertMeaage">
Please, enter book author or its title
</div>
)}
{successMessage && (
<div className="successMessage">Book is successfully added!</div>
)}
<div className="BookForm">
<h3>Add book</h3>
<input
name="title"
type="text"
placeholder="Enter book title"
value={book.title}
onChange={onChange}
/>
<input
name="author"
type="text"
placeholder="Enter book author"
value={book.author}
onChange={onChange}
/>
<button className="submitBtn" onClick={addBook}>
Send
</button>
</div>
<div>
<h4>Recently added books:</h4>
<div key={book.id}>
{books.map((book) => (
<div className="bookItem">
{editMode !== book.id ? (
<>
<span className="titleAuthor">Title: </span>
<i>«{book.title}» </i>
<span className="titleAuthor">Author: </span>{" "}
<i>{book.author}</i>
<button
onClick={() => deleteBook(book.id)}
className="deleteBtn"
>
X
</button>
<button onClick={() => editBook(book)} className="editBtn">
Edit
</button>
</>
) : (
<form className="form">
<input
name="title"
type="text"
defaultValue={book.title}
onChange={(e) => setTitleValue(e.target.value)}
/>
<input
name="author"
type="text"
defaultValue={book.author}
onChange={(e) => setAuthorValue(e.target.value)}
/>
<button
className="saveBtn"
onClick={() => saveChanges(book.id)}
>
Save
</button>
</form>
)}
</div>
))}
</div>
</div>
</div>
);
}
export default App;
<-- Whenever I try to update user info,I am not getting the updated values.But when I reload the page,I get the updated values.Is there a way to get the updated values whenever I hit the update button which is in MiddlePanel? Right now I am fetching all users in loadUsers. -->
class Home extends Component {
state = {
loadUsers: [],
currentUser: null,
};
async componentDidMount() {
const res = await axios.get("http://localhost:5000/users");
this.setState({ loadUsers: res.data });
}
setUser = (currentUser) => {
this.setState({ currentUser });
};
render() {
return (
<Fragment>
<div className="row">
<div className="col-md-3" style={{ backgroundColor: "#303F9F" }}>
<Typography variant="h6">List all Counsellors</Typography>
{this.state.loadUsers.map((user) => {
const { _id, firstname, lastname } = user;
return (
<div key={_id}>
<PrimaryButton
onClick={(e) => {
this.setUser(user);
}}
>
{firstname} {lastname}
</PrimaryButton>
</div>
);
})}
</div>
<div className="col-md-4">
{this.state.currentUser && (
<div>
<MiddlePanel user={this.state.currentUser} />
</div>
)}
</div>
</div>
</Fragment>
);
}
}
export default Home;
Here is my middlepanel code
const MiddlePanel = ({ user }) => {
const [data, setData] = useState({
firstname: "",
lastname: "",
email: "",
phoneNo: "",
});
const { firstname, lastname, email, phoneNo } = data;
useEffect(() => {
const fetchUser = async () => {
const res = await axios.get(`http://localhost:5000/users/${user._id}`);
setData({
firstname: res.data.firstname,
lastname: res.data.lastname,
email: res.data.email,
phoneNo: res.data.phoneNo,
});
};
fetchUser();
}, [user._id]);
const handleChange = (e) => {
const { name, value } = e.target;
setData({ ...data, [name]: value });
};
const handleSubmit = async (e) => {
e.preventDefault();
const newUser = { firstname, lastname, email, phoneNo };
try {
const config = {
headers: {
"Content-Type": "application/json",
},
};
const body = JSON.stringify(newUser);
await axios.patch(
`http://localhost:5000/users/${user._id}`,
body,
config
);
} catch (err) {
console.log(err);
}
};
return (
<div>
<Form onSubmit={handleSubmit}>
<Input
type="text"
name="firstname"
onChange={handleChange}
value={data.firstname}
/>
<Input
type="text"
name="lastname"
onChange={handleChange}
value={data.lastname}
/>
<Input
type="email"
name="email"
onChange={handleChange}
value={data.email}
/>
<Input
type="tel"
name="phoneNo"
onChange={handleChange}
value={data.phoneNo}
/>
<PrimaryButton>Update</PrimaryButton>
</Form>
</div>
);
};
I want to display the updated user info which I am doing in the Middlepanel
try this code , I tested this in codesandbox it works
import React, { Component, Fragment } from "react";
import axios from "axios";
class Home extends Component {
state = {
loadUsers: [],
currentUser: null
};
async componentDidMount() {
const res = await axios.get("https://reqres.in/api/users?page=2");
this.setState({ loadUsers: res.data.data });
}
setUser = (currentUser) => {
console.log(currentUser);
this.setState({ currentUser });
};
render() {
return (
<Fragment>
<div className="row">
<div className="col-md-3" style={{ backgroundColor: "#303F9F" }}>
{/* <Typography variant="h6">List all Counsellors</Typography> */}
{this.state.loadUsers
? this.state.loadUsers.map((user) => {
const { _id, first_name, lastname } = user;
return (
<div key={_id}>
<button onClick={()=> this.setUser(first_name)}>
{first_name} {lastname}
</button>
</div>
);
})
: null}
</div>
<div className="col-md-4">
{this.state.currentUser && <div>{this.state.currentUser}</div>}
</div>
</div>
</Fragment>
);
}
}
export default Home;
I have a dashboard that shows the future and past lessons. Future lessons refresh every minute. Generally, the state doesn't change. I have a feedback form at the pastLessons.js file. When I fill the form data and
"Future lessons component" (futureLessons.js) refresh all form data cleared.
Dashboard.js
import React, { Fragment, useEffect } from 'react';
import { connect } from 'react-redux';
import FutureLessons from './futureLessons';
import PastLessons from './pastLessons';
import { getCurrentProfile } from '../../actions/profile';
const Dashboard = ({
getCurrentProfile,
auth: { user },
profile: { profile, loading },
}) => {
useEffect(
() => {
getCurrentProfile();
},
[getCurrentProfile]
);
return (
<Fragment>
<h1 className='large text-primary'>Dashboard</h1>
<p className='lead'>
<i className='fas fa-user' /> Welcome {user && user.name}
</p>
<Fragment>
<FutureLessons />
<PastLessons />
</Fragment>
</Fragment>
);
};
const mapStateToProps = (state) => ({
auth: state.auth,
profile: state.profile,
});
export default connect(mapStateToProps, { getCurrentProfile })(Dashboard);
pastlessons.js
import React, { useEffect } from 'react'
import { connect } from 'react-redux'
import DataTable, { memoize } from 'react-data-table-component'
import { Tab } from 'semantic-ui-react'
import {
getPastSlots,
deleteStudentSlot,
getPastSlotsInitial,
getFeedbacks
} from '../../actions/index'
import moment from 'moment'
import FeedBackTeacher from './feedBackTeacher'
import { Link } from 'react-router-dom'
const PastLessons = ({
getPastSlotsInitial,
studentSlot,
getPastSlots,
getFeedbacks,
user,
feedbacks
}) => {
useEffect(() => {
(async function () {
try {
await getPastSlotsInitial()
await getFeedbacks()
} catch (e) {
console.error(e)
}
})()
}, [getPastSlotsInitial, getFeedbacks])
const columns = memoize(clickHandler => [
...
])
const ExpanableComponent = ({ data }) => (
<div className='box-sh-2-wh p-1 m'>
{data.lesson && (
<Tab
className='text-left'
panes={[
{
menuItem: 'Teacher\'s Feedback',
render: () => (
<Tab.Pane>
{feedbacks.find(fb => fb._id === data._id)
.evaluatedByTeacher ? (
<div className='break-word'>
<FeedBackTeacher
data={feedbacks.find(fb => fb._id === data._id)}
/>
</div>
) : null}
</Tab.Pane>
)
}
]}
/>
</div>
)
return (
<div className='box-sh-1-wh mt-3'>
{(studentSlot &&
studentSlot.pastSlots &&
studentSlot.pastSlots.length > 0) && (feedbacks && feedbacks.length>0) ? (
<DataTable
title='Previous Lessons'
data={studentSlot.pastSlots}
columns={columns()}
pagination
dense
highlightOnHover
expandableRows
expandableRowsComponent={<ExpanableComponent />}
expandOnRowClicked
/>
) : null}
</div>
)
}
const mapStateToProps = state => ({
studentSlot: state.studentSlot,
feedbacks: state.studentSlot.feedbacks,
user: state.auth.user
})
export default connect(mapStateToProps, {
getPastSlots,
deleteStudentSlot,
getPastSlotsInitial,
getFeedbacks
})(PastLessons)
FeedbackTeacher.js
import React, { useEffect, useState } from 'react'
import { connect } from 'react-redux'
import { createTeacherFeedBack } from '../../actions/index'
import { withRouter } from 'react-router-dom'
import { setAlert } from '../../actions/alert'
const FeedBackTeacher = ({ data, createTeacherFeedBack }) => {
const [formData, setFormData] = useState({
pronounciation: '',
vocabulary: '',
grammarCorrection: '',
recommendation: '',
teacherNote: '',
})
useEffect(() => {
data &&
setFormData({
pronounciation: !data.pronounciation ? '' : data && data.pronounciation,
vocabulary: !data.vocabulary ? '' : data && data.vocabulary,
grammarCorrection: !data.grammarCorrection
? ''
: data && data.grammarCorrection,
recommendation: !data.recommendation ? '' : data && data.recommendation,
teacherNote: !data.teacherNote ? '' : data && data.teacherNote,
// teacher_name: !data.teacher_name ? '' : data.teacher_name
})
}, [data])
const {
pronounciation,
vocabulary,
grammarCorrection,
recommendation,
teacherNote
} = formData
const onChange = (e, name) => {
setFormData({ ...formData, [e.target.name]: e.target.value })
}
const onSubmit = e => {
e.preventDefault()
const id = data._id
setFormData({ ...formData, user_name: data.student_name })
createTeacherFeedBack(formData, id, true)
setAlert('Thank you for your Feedback', 'success')
}
return (
<div>
<form className='form text-left evaluation' onSubmit={e => onSubmit(e)}>
<div>
<div className='form-group colspan-2'>
<textarea
placeholder='Pronounciation'
name='pronounciation'
value={pronounciation}
onChange={e => onChange(e)}
/>
<small className='form-text'>Pronounciation</small>
</div>
<div className='form-group colspan-2'>
<textarea
placeholder='Vocabulary'
name='vocabulary'
value={vocabulary}
onChange={e => onChange(e)}
/>
<small className='form-text'>Vocabulary</small>
</div>
<div className='form-group colspan-2'>
<textarea
placeholder='Grammar Correction'
name='grammarCorrection'
value={grammarCorrection}
onChange={e => onChange(e)}
/>
<small className='form-text'>Grammar Correction</small>
</div>
<div className='form-group colspan-2'>
<textarea
placeholder='Recommendation'
name='recommendation'
value={recommendation}
onChange={e => onChange(e)}
/>
<small className='form-text'>Recommendation</small>
</div>
<div className='form-group colspan-2'>
<textarea
placeholder='Teacher Note'
name='teacherNote'
value={teacherNote}
onChange={e => onChange(e)}
/>
<small className='form-text'>Other Notes</small>
</div>
<div></div>
<input
type='submit'
value='Submit'
className='btn btn-primary my-1'
/>
</div>
</form>
</div>
)
}
export default connect(null, { createTeacherFeedBack, setAlert })(
withRouter(FeedBackTeacher)
)
futureLessons.js similar to pastLesson.js
futureLessons.js
const FutureLessons = ({
studentSlot,
getFutureSlots,
deleteStudentSlot,
user,
}) => {
useEffect(() => {
getFutureSlots()
}, [getFutureSlots])
useEffect(() => {
const interval = setInterval(() => {
getFutureSlots();
}, 60000);
return () => clearInterval(interval);
}, [getFutureSlots]);
I tried to use redux-form but nothing changed. "pastLesson.js" file state doesn't change. Only futureLessons.js refreshes every minute. Redux dev tool image like this:
Redux dev tool image
States are equal but my form all data cleared.