Material UI Avatar Image Upload - reactjs

I managed it to make an Avatar chooser, but I don't know how to save the picture in Firebase or how to even save it as a Profile picture.
This is how it looks like:
This comes out if I click on the button:
I can choose a pic, but it just not saving it anywhere and also not displaying the picture in the avatar.
My code:
function Profile(props, navigation) {
const classes = useStyles();
const user = useUser(props.route.params.uid);
const [time, setTime] = useState("7:30");
const [timing, setTiming] = useState([]);
const [timeAfternoon, setTimeAfternoon] = useState("7:30");
const [timingAfternoon, setTimingAfternoon] = useState([]);
const [sickDaysStart, setSickDaysStart] = useState(Date.now());
const [sickDaysEnd, setSickDaysEnd] = useState(Date.now());
const [sickDaysConfirm, setSickDaysConfirm] = useState([]);
const [donwloadURL, setDownloadURL] = useState([]);
const onLogout = () => {
firebase.auth().signOut();
};
function handelSickDaysStart(e) {
setSickDaysStart(e.target.value);
}
function handelSickDaysEnd(e) {
setSickDaysEnd(e.target.value);
}
function handleTime(e) {
setTime(e.target.value);
}
function handleTimeAfternoon(e) {
setTimeAfternoon(e.target.value);
}
function delayMorning() {
db.collection("delayInTheMorning")
.doc()
.set({
time,
user,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setTiming([...timing, { time }]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function delayAfternoon() {
db.collection("delayInTheAfternoon")
.doc()
.set({
timeAfternoon,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setTimingAfternoon([...timingAfternoon, { timeAfternoon }]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function sickDaysStartEnd() {
db.collection("DaysofSickness")
.doc()
.set({
sickDaysStart,
sickDaysEnd,
user,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setSickDaysConfirm([
...sickDaysConfirm,
{ sickDaysStart, sickDaysEnd },
]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function isCurrentUserProfile() {
if (props.route.params.uid === firebase.auth().currentUser.uid) {
return true;
} else {
return false;
}
}
async function handleFileInputChange(e) {
const files = e.target.files;
const file = files[0];
const storage = firebase.storage();
const usersImageRef = storage
.ref()
.child(`users/${user.uid}/profilepicture.jpg`);
const snap = await usersImageRef.put(file);
const donwloadURL = await snap.ref.getDownloadURL();
setDownloadURL(donwloadURL);
await firebase.auth().currentUser.updateProfile({ photoURL: donwloadURL });
}
if (user === null) {
return <div className={classes.root} />;
}
return (
<ScrollView style={styles.root}>
<Container className={classes.div}>
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
onChange={handleFileInputChange}
/>
<label>
<IconButton>
<Avatar
src="../assets/ana.png"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
</label>
<Typography className={classes.text}> {user.name} </Typography>
<Typography className={classes.text}> {user.email} </Typography>
{isCurrentUserProfile() ? (
<Button
className={classes.btn}
size="large"
variant="outlined"
onClick={() => onLogout()}
>
Logout
</Button>
) : null}
</Container>
<Card className={classes.div}>
{/* //Verspätung */}
<CardContent className={classes.cardBackGround}>
<Typography variant="h5" className={classes.cardTyp}>
{" "}
Verspätung{" "}
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
onChange={(value) => {
handleTime(value);
}}
/>
<Button className={classes.cardBtn} onClick={() => delayMorning()}>
Absenden
</Button>
</Container>
</CardContent>
{/* //Krankenmledungen */}
<CardContent className={classes.cardBackGround}>
<Typography variant="h5" className={classes.cardTyp}>
Krankenmledungen
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="date"
label="Von"
type="date"
defaultValue="2021-09-14"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
onChange={(value) => {
handelSickDaysStart(value);
}}
/>
<TextField
id="date"
label="bis"
type="date"
defaultValue="2021-09-20"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
onChange={(value) => {
handelSickDaysEnd(value);
}}
/>
</Container>
<Button
className={classes.cardBtnKM}
onClick={() => sickDaysStartEnd()}
>
Absenden
</Button>
</CardContent>
{/* //Verspätung Abolung*/}
<CardContent className={classes.cardBackGround}>
<Typography variant="h5" className={classes.cardTyp}>
{" "}
Verspätung Abholung
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
onChange={(value) => {
handleTimeAfternoon(value);
}}
/>
<Button
className={classes.cardBtn}
onClick={() => delayAfternoon()}
>
Absenden
</Button>
</Container>
</CardContent>
</Card>
{/* <List> */}
{/* Verspätungs Liste */}
{timing.map((item) => {
return (
<List className={classes.lists}>
<ListItem className={classes.list1}>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Verspätung in der Früh ${item.time}`}
/>
</ListItem>
</List>
);
})}
{/* Krankmeldung */}
{timingAfternoon.map((item) => {
return (
<List className={classes.lists}>
<ListItem className={classes.list}>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Verspätung bei der Abholung ${item.timeAfternoon}`}
/>
</ListItem>
</List>
);
})}
{/* Verspätungs Nachmittag */}
{sickDaysConfirm.map((item) => {
return (
<List className={classes.lists}>
<ListItem className={classes.list}>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Krankmeldung von ${item.sickDaysStart} bis ${item.sickDaysEnd}`}
/>
</ListItem>
</List>
);
})}
</ScrollView>
);
}
There is also a imagePicker from Expo, I was thinking of trying that but I'm just not sure.

If you want to change the profile picture of a user you can use this code:
import { getAuth, updateProfile } from "firebase/auth";
const auth = getAuth();
updateProfile(auth.currentUser, {
displayName: "User Name", photoURL: "https://example.com/jane-q-user/profile.jpg"
}).then(() => {
// Profile updated!
// ...
}).catch((error) => {
// An error occurred
// ...
});
You can find more info about it here.
To get the picture URL you would need to upload it to Firebase Storage and get the downloadURL:
import { getStorage, ref, uploadBytes, getDownloadURL } from "firebase/storage";
const storage = getStorage();
const storageRef = ref(storage, 'some-child');
// 'file' comes from the Blob or File API
uploadBytes(storageRef, file).then((snapshot) => {
console.log('Uploaded a blob or file!');
getDownloadURL(snapshot.ref).then((downloadURL) => {
console.log('File available at', downloadURL);
});
});
I would also change the input to not have multiple files to select. If you would share more of your code I can integrate those code snippets in your code in case you have problems with it.
UPDATE:
Here is the whole example. I see you use the old SDK so the example is with it:
function Profile(props, navigation) {
const classes = useStyles();
const user = useUser(props.route.params.uid);
const delay = DayandTime();
const [time, setTime] = useState("7:30");
const [timing, setTiming] = useState([]);
const [downloadurl, setDU] = useState("/images/example.jpg");
const [timeAfternoon, setTimeAfternoon] = useState("7:30");
const [timingAfternoon, setTimingAfternoon] = useState([]);
const [sickDaysStart, setSickDaysStart] = useState(Date.now());
const [sickDaysEnd, setSickDaysEnd] = useState(Date.now());
const [sickDaysConfirm, setSickDaysConfirm] = useState([]);
const onLogout = () => {
firebase.auth().signOut();
};
function handelSickDaysStart(e) {
setSickDaysStart(e.target.value);
}
function handelSickDaysEnd(e) {
setSickDaysEnd(e.target.value);
}
function handleTime(e) {
setTime(e.target.value);
}
function handleTimeAfternoon(e) {
setTimeAfternoon(e.target.value);
}
function delayMorning() {
db.collection("delayInTheMorning")
.doc()
.set({
time,
user,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setTiming([...timing, { time }]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function delayAfternoon() {
db.collection("delayInTheAfternoon")
.doc()
.set({
timeAfternoon,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setTimingAfternoon([...timingAfternoon, { timeAfternoon }]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function sickDaysStartEnd() {
db.collection("DaysofSickness")
.doc()
.set({
sickDaysStart,
sickDaysEnd,
user,
})
.then(() => {
//If you wish to push the written data to your local state, you can do it here
setSickDaysConfirm([
...sickDaysConfirm,
{ sickDaysStart, sickDaysEnd },
]);
console.log("Documents saved succesfully");
})
.catch((err) => {
console.log(err);
});
}
function isCurrentUserProfile() {
if (props.route.params.uid === firebase.auth().currentUser.uid) {
return true;
} else {
return false;
}
}
if (user === null) {
return <div className={classes.root} />;
}
async function handleFileInputChange(e) {
const files = e.target.files;
const file = files[0];
const storage = firebase.storage();
const usersImageRef = storage
.ref()
.child(`users/${user.uid}/profilepicture.jpg`);
const snap = await usersImageRef.put(file);
const downloadURL = await snap.ref.getDownloadURL();
setDU(downloadURL);
await firebase.auth().updateProfile({ photoURL: downloadURL });
}
return (
<ScrollView style={styles.root}>
<Container className={classes.div}>
<input
accept="image/*"
className={classes.input}
id="contained-button-file"
multiple
type="file"
onChange={handleFileInputChange}
/>
<label htmlFor="contained-button-file">
<IconButton>
<Avatar
src="/images/example.jpg"
style={{
margin: "10px",
width: "60px",
height: "60px",
}}
/>
</IconButton>
</label>
<Typography className={classes.text}> {user.name} </Typography>
<Typography className={classes.text}> {user.email} </Typography>
{isCurrentUserProfile() ? (
<Button
className={classes.btn}
size="large"
variant="outlined"
onClick={() => onLogout()}
>
Logout
</Button>
) : null}
</Container>
<Card className={classes.div}>
{/* //Verspätung */}
<CardContent>
<Typography variant="h5" className={classes.cardTyp}>
{" "}
Verspätung{" "}
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
onChange={(value) => {
handleTime(value);
}}
/>
<Button className={classes.cardBtn} onClick={() => delayMorning()}>
Absenden
</Button>
</Container>
</CardContent>
{/* //Krankenmledungen */}
<CardContent className={classes.cardKrankmeldung}>
<Typography variant="h5" className={classes.cardTyp}>
{" "}
Krankenmledungen{" "}
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="date"
label="Von"
type="date"
defaultValue="2021-09-14"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
onChange={(value) => {
handelSickDaysStart(value);
}}
/>
<TextField
id="date"
label="bis"
type="date"
defaultValue="2021-09-20"
className={classes.textField}
InputLabelProps={{
shrink: true,
}}
onChange={(value) => {
handelSickDaysEnd(value);
}}
/>
</Container>
<Button
className={classes.cardBtnKM}
onClick={() => sickDaysStartEnd()}
>
Absenden
</Button>
</CardContent>
{/* //Verspätung Abolung*/}
<CardContent>
<Typography variant="h5" className={classes.cardTyp}>
{" "}
Verspätung Abholung
</Typography>
<Container className={classes.cardContainer}>
<TextField
id="time"
label="Zeit"
type="time"
defaultValue="07:30"
InputLabelProps={{
shrink: true,
}}
inputProps={{
step: 300, // 5 min
}}
onChange={(value) => {
handleTimeAfternoon(value);
}}
/>
<Button
className={classes.cardBtn}
onClick={() => delayAfternoon()}
>
Absenden
</Button>
</Container>
</CardContent>
</Card>
<List>
{/* Verspätungs Liste */}
<ListItem>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Verspätung in der Früh ${delay}`}
/>
</ListItem>
{/* Verspätungs Krankmeldung */}
<ListItem>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Krankmeldung ${delay}`}
/>
</ListItem>
{/* Verspätungs Nachmittag */}
<ListItem>
<ListItemAvatar>
<Avatar></Avatar>
</ListItemAvatar>
<ListItemText
primary={user.name}
secondary={`Verspätung Nachmittag ${delay}`}
/>
</ListItem>
</List>
</ScrollView>
);
}
const mapStateToProps = (store) => ({
currentUser: store.userState.currentUser,
posts: store.userState.posts,
following: store.userState.following,
});
export default connect(mapStateToProps, null)(Profile);
const useStyles = makeStyles({
root: {
backgroundColor: "white",
},
div: {
marginTop: 20,
marginLeft: 15,
marginRight: 15,
backgroundColor: "white",
},
avatar: {
marginBottom: 10,
},
btn: {
marginTop: 10,
width: 250,
marginBottom: 30,
},
text: {
fontSize: 25,
marginTop: 10,
},
cardTyp: {
textAlign: "left",
paddingLeft: 13,
},
cardBtn: {
marginTop: 20,
marginLeft: 30,
},
cardBtnKM: {
marginTop: 20,
marginLeft: 10,
},
cardContainer: {
display: "flex",
},
});
const styles = StyleSheet.create({
root: {
backgroundColor: "white",
},
});

Related

can't edit data in Textfield in reactjs

I'm trying to edit the api data on a Mui datagrid. I want a modal form to pop on clicking the edit icon. Everything works fine, I'm getting the data to be edited and all that. thing is the data I'm getting in textfield for edit, is not changing the value. it's not taking any inputs I'm giving, it stays the same. what should I do to make the textfields editable ? Thanks in advance.
export default function ContactsCard(props) {
const [ContactData, setContactData] = useState([]);
const [open, setOpen] = useState(false);
const [formInputData, setformInputData] = useState(
{
name: '',
details: '',
}
);
const handleChange = (evnt) => {
const newInput = (data) => ({
...data,
[evnt.target.name]: evnt.target.value
});
setformInputData(newInput);
}
const showData = () => {
axios.get('http://localhost:8006/api/v2/get/beneficiaries-list').then(function (res) {
try {
var result = res.data;
// console.log(result.data)
setContactData(result.data)
}
catch (error) {
console.log(error)
}
})
}
const handleSubmit = (evnt) => {
evnt.preventDefault();
const formData = new FormData(); //formdata object
formData.append('nickname', formInputData.name); //append the values with key, value pair
formData.append('target', formInputData.details);
const config = {
headers: { 'content-type': 'multipart/form-data' }
}
axios.post('http://localhost:8006/api/v2/save/beneficiary', formData, config)
.then(response => {
if (response.data.success === true) {
showData()
alert(response.data.message)
}
})
.catch(error => {
alert(error.message);
});
setformInputData({ name: "", details: "" });
setOpen(false);
}
const handleEdit = (id) => {
var edit_id = id.row.id
console.log(edit_id)
setOpen(true)
setformInputData(ContactData.find((data) => data.id === edit_id))
setOpen(true)
}
const handleOpen = () => setOpen(true)
const handleClose = () => setOpen(false);
useEffect(() => {
showData();
}, [])
const handleDelete = (id) => {
var del_id = id.row.id
console.log(del_id)
axios.post('http://localhost:8006/api/v2/remove/beneficiary/', { id: del_id }).then(res => {
console.log(res.data)
if (res.data.success === true) {
alert(res.data.message)
showData();
console.log('ajh');
}
})
};
const columns = [
{ field: 'name', headerName: 'Nick Name', width: '130' },
{ field: 'details', headerName: 'Deposit address', width: '130' },
{
field: 'actions',
type: 'actions',
width: '130',
headerName: 'Actions',
cellClassName: 'actions',
renderCell: (id) => {
return (
<>
<IconButton color="primary" onClick={(e) => { handleEdit(id) }}>
<EditIcon />
</IconButton>
<IconButton color="error" onClick={(e) => {
handleDelete(id)
}}>
<DeleteIcon />
</IconButton>
</>
);
},
},
];
return (
<Card {...props}>
<CardContent>
<ContactDataGrid rows={ContactData} columns={columns} />
<Modal
aria-labelledby="transition-modal-title"
aria-describedby="transition-modal-description"
open={open}
onClose={handleClose}
closeAfterTransition
BackdropComponent={Backdrop}
BackdropProps={{
timeout: 500,
}}
>
<Fade in={open}>
<FormControl sx={style} mt={1} >
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
Edit Contact
</Typography>
<Stack flexDirection='column' gap={1.5} mt={1}>
<TextField autoFocus required
id="filled-hidden-label-small"
label="Nick Name" variant="outlined" size="small"
onChange={handleChange}
value={formInputData.name}
name="Nick Name"
className="form-control"
/>
<TextField required
id="filled-hidden-label-small"
label="Deposit Address" variant="outlined" size="small"
onChange={handleChange}
value={formInputData.details}
name="Amount"
className="form-control"
/>
</Stack>
<Stack flexDirection='row' justifyContent={'center'} gap={1.5} mt={1}>
<Button
variant="contained"
type="submit" color="error"
onClick={handleClose}
sx={{ alignSelf: 'center' }} >Cancel</Button>
<Button
variant="contained"
type="submit"
onClick={handleSubmit}
sx={{ alignSelf: 'center', backgroundColor: '#000073' }} >Submit</Button>
</Stack>
</FormControl>
</Fade>
</Modal>
</CardContent>
</Card>
);
}
Your handleChange function is updating the new value in event.target.name but, the name doesn't match with the value. You can try changing the name to match the value getter:
<TextField autoFocus required
id="filled-hidden-label-small"
label="Nick Name" variant="outlined" size="small"
onChange={handleChange}
value={formInputData.name}
name="name" // this changed
className="form-control"
/>
<TextField required
id="filled-hidden-label-small"
label="Deposit Address" variant="outlined" size="small"
onChange={handleChange}
value={formInputData.details}
name="details" // this changed
className="form-control"
/>

Problems integrating react-hooks-forms with material ui

**Hello folks,
my problem is there are no error messages displayed even if nothing is inside. Anyone know what I did wrong? The code is in the attachment.Everything works except the message when nothing was selected in the autocomplete
.
.
.
Am I doing it wrong with the formprovider? Or should I better take the register method from the useForm - Methods? Or schould the text field itself have a controller?
**
const validationSchema = yup.object().shape({
selKategorie: yup.string().required("Select Validation Field is Required"),
}).required();
function Anlage(props) {
const { status, data, isError, isFetching } = useAnlegeData();
const [step, setStep] = React.useState(0);
const methods = useForm({
resolver: yupResolver(validationSchema),
});
const { handleSubmit, formState: { errors }, watch } = methods;
const labels = ['First Step', 'Secound Step', 'Confirmation'];
const handleSteps = (step) => {
switch (step) {
case 0:
return <FirstStep kategorien={data.Kategorie} methods={methods} />
case 1:
return <SecoundStep />
case 2:
return <Confirm />
default:
return <FirstStep />
}
}
return(
<>
<MyNavbar BACK={true}/>
{status.loading && <Loading /> }
<Container component="main" sx={{ mb: 4}}>
<Paper variant="outlined"
sx={{ my: { xs: 3, md: 6 }, p: { xs: 2, md: 3 } }}>
<Stepper activeStep={step} sx={{ py: 3 }} alternativeLabel>
{labels.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
{status === 'success' &&
handleSteps(step)}
</Paper>
<p>{errors?.selKategorie?.message}</p>
</Container>
</>
)
}
export default function FirstStep(props) {
return(
<>
<FormProvider {...props.methods}>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<ControlledAutocomplete
name="selKategorie"
options={props.kategorien}
getOptionLabel={(option) => {
console.log('get option label: ',option);
return option.MASKENKEY; }
}
renderInput={(params) => <TextField {...params} label="Ticketkategorie" margin="normal" />}
defaultValue={null}
/>
</Grid>
</Grid>
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
<Button
variant="contained"
sx={{ mt: 3, ml: 1 }}
disabled={false}
color="primary"
onClick={() => null}
>
Next
</Button>
</Box>
</FormProvider>
</>
)
}
const ControlledAutocomplete = ({ options = [], renderInput, getOptionLabel, defaultValue, name}) => {
const { control, formState: { errors } } = useFormContext();
let isError = true;
let errorMessage = "";
if (errors && errors.hasOwnProperty(name)) {
isError = true;
errorMessage = errors[name].message;
}
return (
<Controller
render={({ field: { onChange } }) => (
<Autocomplete
options={options}
getOptionLabel={getOptionLabel}
//renderOption={renderOption}
renderInput={renderInput}
onChange={onChange}
/>
)}
onChange={([, data]) => {
return data
}}
name={name}
control={control}
defaultValue={defaultValue}
errorMessage={errorMessage}
error={isError}
/>
)
}

My react component return statement fails to render but console.log shows exactly what I need

I am new to react and working on a react video player. I'm having issue implementing the comment section.
This is my videoplayer component itself.
export default function VidPlayer() {
// useStates
const [state, setState] = useState({
playing: true,
});
const [comments, setComments] = useState([]);
const [comment, setComment] = useState("");
const { playing } = state;
const playerRef = useRef(null);
// declaring functions for video player buttons
const handlePlayPause = () => {
setState({ ...state, playing: !state.playing });
};
const handleRewind = () => {
playerRef.current.seekTo(playerRef.current.getCurrentTime() - 5);
};
const handleFoward = () => {
playerRef.current.seekTo(playerRef.current.getCurrentTime() + 5);
};
const handleStop = () => {
playerRef.current.seekTo(0);
setState({ playing: !state.playing });
};
// declaring functions for comment section
const addComments = () => {
if (comment) {
setComments({...comments, comment});
setComment("");
console.log("Hello", comments);
}
};
const handleComment = (e) => {
setComment(e.target.value);
};
return (
<div>
<AppBar style={{ background: "#e6880e" }} position="static">
<Toolbar>
<Typography variant="h6" component="div" sx={{ flexGrow: 1 }}>
Favour's Video Player
</Typography>
</Toolbar>
</AppBar>
{/* container for the videoplayer, buttons and comment section */}
<div className="container">
<>
{/* videoplayer */}
<div className="reactPlayer one">
<ReactPlayer
ref={playerRef}
url="https://www.youtube.com/watch?v=1_ATK0BLc8U&t=3s"
playing={playing}
controls
/>
</div>
{/* buttons */}
<div className="btn-stack two">
<Stack spacing={2} direction="row">
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handlePlayPause}
>
Play
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleRewind}
>
Rewind{" "}
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleFoward}
>
Forward{" "}
</Button>
<Button
style={{ background: "#e6880e" }}
size="small"
variant="contained"
onClick={handleStop}
>
Stop
</Button>
</Stack>
</div>
{/* comment section */}
<div className="comment three">
<Comment userComs={comments} />
<TextField
placeholder="add comment"
size="small"
variant="outlined"
onChange={handleComment}
value={comment}
/>
<Button
style={{ background: "#e6880e", marginLeft: '1em' }}
onClick={addComments}
variant="contained"
size="small"
>
Send
</Button>
</div>
</>
</div>
</div>
);
}
It takes in this comments component towards the end.
export default function commentList(props) {
console.log("Hello brian", props.userComs);
const { userComs } = props;
if (Object.keys(userComs).length > 0) {
console.log(userComs);
// userComs.forEach((element) => {
// console.log("Im in", userComs);
Object.values(userComs).forEach(val => {
// console.log("Im in", userComs);
// console.log(val);
return (
<div>
<List
sx={{ width: "100%", maxWidth: 360, bgcolor: "background.paper" }}
>
<ListItem alignItems="flex-start">
<ListItemAvatar>
<Avatar alt="Remy Sharp" src="/static/images/avatar/1.jpg" />
</ListItemAvatar>
<ListItemText
secondary={
<React.Fragment>
<Typography
sx={{ display: "inline" }}
component="span"
variant="body2"
color="text.primary"
>
Ali Connors
</Typography>
{val}
</React.Fragment>
}
/>
</ListItem>
<Divider variant="inset" component="li" />
</List>
</div>
);
});
} else {
return <div></div>;
}
}
This is the Front-End enter image description here
Unfortunately, when I enter a comment and click send, the screen goes blank and console throws a "nothing was returned from render" error. Can someone help me check what is wrong and how I can fix this please?
As the error says, the component isn't returning anything.
Object.values(userComs).forEach(val => {
should be
return Object.values(userComs).map(val => {
because forEach doesn't return anything and the JSX returned in each iteration will not be used anywhere, but map returns a new array that React can use.
BTW make sure to give a key prop to each div that is returned from the callback.
<div key={val}> // assuming `val` is unique

Changing class component to functional component in React

I have this code and tried to convert it to functional component and I am stuck. I have a form in return() part that passes the value to the state and then to props? via mapStateToProps as far as I understand... But, switching to function() component, I am lost what I have to do here.
class Login extends Component {
state = {
login: '',
password: '',
keepLogged: false
};
changeValue = event => {
event.preventDefault();
const value = event.target.value;
const name = event.target.name;
this.setState({
[name]: value
});
};
loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ login, password });
};
render() {
const { login, password } = this.state;
return (
<LoginWrapper>
<Container style={{ border: '1px solid #757575', padding: '5%' }}>
<Row>
<Col style={{ textAlign: 'right', marginRight: '25px' }}>
</Col>
</Row>
<Row>
<Col>
<LoginHeader>Log In to Your Account</LoginHeader>
</Col>
</Row>
<Row>
<Col>
<LoginForm>
<FormControl
name='login'
type='text'
placeholder='Username/Email'
value={login}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
/>
<FormControl
name='password'
type='password'
placeholder='Password'
value={password}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
/>
<Button
variant='info'
value='Log In'
onClick={() => this.loginUser()}
>
Log In
</Button>
</LoginForm>
</Col>
</Row>
<Row>
<Col>
<LoginBottom
onClick={() => history.push('/registration')}
style={{ marginTop: '30px' }}
>
Need an account?{' '}
<Link style={{ color: '#007bff' }}>Sign Up</Link>
</LoginBottom>
</Col>
</Row>
</Container>
</LoginWrapper>
)
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
});
export default connect(null, mapDispatchToProps)(Login);
So far, I have done this. I am stuck here. Tried to introduce useState for each login, password, and keepLogged but failed :/
function Login(props) {
const [inputs, setInputs] = useState({
// you can login with email or username
login: '',
password: '',
keepLogged: false
});
const { login, password } = inputs;
function handleChange(e) {
e.preventDefault();
const { name, value } = e.target;
setInputs(inputs => ({ ...inputs, [name]: value }));
}
const loginUser = () => {
const setInputs = inputs;
const { requestSignIn } = props;
requestSignIn({ setInputs });
};
return (
<Grid container component='main' className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<div>
<img src={Logo} style={{ width: 300 }} />
</div>
<Typography component='h1' variant='h5'>
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant='outlined'
margin='normal'
required
fullWidth
id='email'
label='Email Address'
value={login}
onChange={handleChange}
name='login'
autoComplete='email'
autoFocus
/>
<TextField
variant='outlined'
margin='normal'
required
fullWidth
name='password'
label='Password'
value={password}
onChange={handleChange}
type='password'
id='password'
autoComplete='current-password'
/>
<FormControlLabel
control={<Checkbox value='remember' color='primary' />}
label='Remember me'
/>
<Button
type='submit'
fullWidth
variant='contained'
color='primary'
value='Log In'
className={classes.submit}
onClick={() => loginUser()}
>
Sign In 🙂
</Button>
<Grid container>
<Grid item xs>
<Link href='#' variant='body2'>
Forgot password?
</Link>
</Grid>
<Grid item>
<Link
variant='body2'
onClick={() => history.push('/registration')}
>
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
<Box mt={5}>
<Copyright />
</Box>
</form>
</div>
</Grid>
</Grid>
)
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
});
export default connect(null, mapDispatchToProps)(Login);
I think you were most of the way there, just a case of clearing up some redundant code.
const [inputs, setInputs] = useState({
login: '',
password: '',
keepLogged: false
});
const { login, password } = inputs;
function handleChange(e) {
e.preventDefault();
const { name, value } = e.target;
// Set the inputs object directly, no need to callback
setInputs({ ...inputs, [name]: value });
}
const loginUser = () => {
const { requestSignIn } = props;
// Login and password are already initialised
requestSignIn({login, password});
};
You may also want to pass the event object to the handler like so:
onChange={e => handleChange(e)}

react fires events for all items and the item selected

I'm trying to fire the onClick event for the item that i clicked on. Not for all items.
<Button onClick = {this.writeComment} varient="outlined" component="span" color="primary">
{!this.state.isComment ? "Write Comment": "Close"}
</Button>
{this.state.isComment ? <Comment onSubmit={this.commentSubmit} commentBody={this.state.comment_body} commentChange={this.handleCommentChange}/> : null}
writeComment function
writeComment = (e) => {
e.preventDefault();
this.setState({
isComment:!this.state.isComment
})
}
this should render a comment form for that item only, not for all items. This is within a map loop.
{this.state.images.length > 0 ? (
this.state.images.map( (img, i) => (
<Grid item sm={12} md={12} key={i} style={{ margin: '30px 0px'}}>
<Paper style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick = {this.writeComment} varient="outlined" component="span" color="primary">
{!this.state.isComment ? "Write Comment": "Close"}
</Button>
{this.state.isComment ? <Comment onSubmit={this.commentSubmit} commentBody={this.state.comment_body} commentChange={this.handleCommentChange}/> : null}
<Button onClick={() => this.deleteImg(img.id)} variant="outlined" component="span" color="primary">
Delete
</Button>
</Paper>
</Grid>
))
) : (
<div>
<Grid item md={8}>
<Typography>No Images yet</Typography>
</Grid>
</div>
)}
</Grid>
{/* Images */}
</Grid>
Full code
import React, { Component } from "react";
import Button from '#material-ui/core/Button';
import TextField from '#material-ui/core/TextField';
import Grid from '#material-ui/core/Grid';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
import ImageUploader from 'react-images-upload';
import Divider from '#material-ui/core/Divider';
import Axios from '../Axios';
import Image from './Image';
import moment from 'moment';
import Comment from './Comment';
class Dashboard extends Component{
constructor(props){
super(props);
this.state = {
image_url: 'http://www.conservewildlifenj.org/images/artmax_1001.jpg',
images: [],
description:'',
upload:false,
isComment:false,
comment_body:''
}
}
handleUpload = file => {
const data = new FormData()
const image = file[0]
// console.log(this.state.description)
// data.append('ourImage', this.state.description)
data.append('ourImage',image, this.state.description )
Axios.post('/images/upload', data).then((response) => {
const newImage = {...response.data}
console.log(newImage);
//update component-state
this.setState({
description:'', // resets title after upload
images: [
{
id: newImage[0].id,
user:{
username: newImage[0].user.username
},
image_title: newImage[0].image_title,
img_url: newImage[0].img_url,
created_at: new Date().toLocaleString().replace(',', ''),
updated_at: new Date().toLocaleString().replace(',', '')
},
...this.state.images
]
})
});
}
handleChange = (e) => {
// e.preventDefault();
this.setState({
[e.target.name]: e.target.value
})
// console.log(this.state.description)
}
handleCommentChange = (e) => {
this.setState({
comment_body: e.target.value
})
}
componentWillMount(){
Axios.get('/images/uploads').then( (response) => {
// let img;
// let imgTitle;
Object.keys(response.data).forEach( (key) => {
console.log(response.data[key]);
this.setState({
images:[ ...this.state.images, response.data[key]]
})
console.log(this.state.images);
});
})
}
componentDidUpdate(prevProps, prevState) {
if (this.state.images.length !== prevState.images.length) {
console.log(this.state.images);
}
// debugger;
}
onUploadClick = (e) => {
e.preventDefault();
this.setState({
upload: !this.state.upload
})
}
deleteImg = (id) => {
Axios.post(`/images/delete/${id}`).then( () => {
this.setState({
images: [ ...this.state.images.filter(img => img.id !== id)]
})
})
}
writeComment = (e) => {
e.preventDefault();
this.setState({
isComment:!this.state.isComment
})
}
commentSubmit = (e) => {
e.preventDefault();
console.log(this.state.comment_body);
// Axios.post('/images/newComment', this.state.comment_body).then( (response )=> {
// const newComment = { ...response.data};
// console.log(newComment);
// this.setState({
// comment_body: ''
// })
// })
}
render(){
const uploader = (
<ImageUploader
withIcon={true}
withPreview={true}
onChange={this.handleUpload}
singleImage={true}
buttonText='Upload an image'
imgExtension={['.jpg', '.gif', '.png', '.gif']}
maxFileSize={5242880}
/>
)
return(
<div>
<Grid container justify="center" spacing={16}>
<Grid item sm={8} md={6} style={{ margin: '40px 0px', padding: '0px 30px'}}>
<Typography align="center" variant="h6">
Welcome to the Dashboard
</Typography>
<Button onClick={this.onUploadClick} variant="outlined" component="span" color="primary">
{/* toggle between Upload or Close
Will be upload by default, else if upload is clicked, close will show.
*/}
{!this.state.upload ? "Upload": "Close"}
</Button>
<br></br>
<br></br>
{this.state.upload ? (
<div>
<TextField
id="outlined-name"
label="Image Title"
name="description"
type="text"
required={true}
fullWidth
style={{ borderRadius: '0px'}}
className=""
value={this.state.description}
onChange={this.handleChange}
margin="normal"
/>
<br></br>
<br></br>
{/* so here what we are saying, if this text field is FILLED show the uploader component
else hide it.
*/}
{this.state.description ? uploader : null}
</div>
):(
null
)}
{this.state.images.length > 0 ? (
this.state.images.map( (img, i) => (
<Grid item sm={12} md={12} key={i} style={{ margin: '30px 0px'}}>
<Paper style={{padding:'20px 20px'}}>
{/* // empty image_title */}
<Typography style={{ padding: '30px 5px', letterSpacing:'8px', textTransform:'uppercase'}} variant="h4" align="center">{img.image_title}</Typography>
<Divider style={{ width: '150px', margin:'10px auto', backgroundColor:'#000000'}} variant="middle" />
<Image image_url={img.img_url} />
<Typography variant="h6" align="center">{img.user.username}</Typography>
<Typography variant="h6" align="center">{moment(img.created_at).calendar()}</Typography>
<Button onClick = {this.writeComment} varient="outlined" component="span" color="primary">
{!this.state.isComment ? "Write Comment": "Close"}
</Button>
{this.state.isComment ? <Comment onSubmit={this.commentSubmit} commentBody={this.state.comment_body} commentChange={this.handleCommentChange}/> : null}
<Button onClick={() => this.deleteImg(img.id)} variant="outlined" component="span" color="primary">
Delete
</Button>
</Paper>
</Grid>
))
) : (
<div>
<Grid item md={8}>
<Typography>No Images yet</Typography>
</Grid>
</div>
)}
</Grid>
{/* Images */}
</Grid>
</div>
)
}
}
export default Dashboard;
onClick ={() => this.writeComment(image.id)} //id of your item
writeComment = (id) => {
this.setState({
isComment: this.state.isComment ? '' : id // check if you state is filled to toggle on/off comment
})
}
{this.state.isComment === image.id ? <Comment onSubmit={this.commentSubmit} commentBody={this.state.comment_body} commentChange={this.handleCommentChange}/> : null}

Resources