i just create this timepicker using mui and momentjs. 2 timepicker, one input, and one button, when user selects particular time like in first picker 8:am and in second one is 9:00am, and enter the slot like 6 so output will be 8:00-8:10, 8:10-8:20, 8:20 - 8:30, 8:40 - 8:50, 8:50 - 9:00. i am done with this to think about logic.
import * as React from "react";
import TextField from "#mui/material/TextField";
import { AdapterDateFns } from "#mui/x-date-pickers/AdapterDateFns";
import { LocalizationProvider } from "#mui/x-date-pickers/LocalizationProvider";
import { TimePicker } from "#mui/x-date-pickers/TimePicker";
import { Box } from "#mui/system";
import moment from "moment";
import { Button, Grid } from "#mui/material";
import Paper from "#mui/material/Paper";
export default function BasicDatePicker() {
const [startTime, setStartTime] = React.useState([]);
const [endTime, setEndTime] = React.useState([]);
return (
<Box
component="main"
sx={{ flexGrow: 1, p: 3 }}
style={{ marginTop: "100px" }}
>
<LocalizationProvider
dateAdapter={AdapterDateFns}
sx={{ flexGrow: 1, p: 3 }}
>
<Box
sx={{
display: "flex",
flexWrap: "wrap",
"& > :not(style)": {
m: "0 auto",
width: 300,
height: 350,
},
}}
>
<Paper elevation={3}>
<Grid container>
<Grid item xs={12} style={{ margin: "25px" }}>
<TimePicker
label="Start Time"
value={startTime}
onChange={(newValue) => {
setStartTime(newValue);
// setStartTime(moment(newValue).add(1, "days"));
// console.log(newValue)
}}
renderInput={(params) => <TextField {...params} />}
/>
</Grid>
<Grid item xs={12} style={{ margin: "25px" }}>
<TimePicker label="End Time"
// disabled
value={endTime}
onChange={(newValue) => {
setEndTime(newValue);
}}
renderInput={(params) => <TextField {...params} />}
/>
</Grid>
<Grid item xs={12} style={{ textAlign: "center" , }}>
{" "}
<TextField id="outlined-basic" label="Slot" variant="outlined"/>
</Grid>
<Grid item xs={12} style={{ textAlign: "center", margin: "10px" }}>
{" "}
<Button variant="contained">Action</Button>
</Grid>
</Grid>
</Paper>
</Box>
</LocalizationProvider>
</Box>
);
}
Here you can use this function, pass the moment objects to the function.
const today = moment();
const someday = moment().add(1,"h");
function getSlots(one, two){
const slots = [];
while(one.unix() < two.unix()){
const tmp = one;
const slot = `${tmp.format("h:mm")}-${one.add(10,"m").format("h:mm")}`;
}
return slots;
}
console.log(getSlots(today, someday,"10 min"));
Related
I need to pass the state value to a different component and I want to use it in the different component.
Code in the first component:
const handleFormSubmit = async (event) => {
event.preventDefault()
console.log(formData)
try {
await axios
.post(`http://localhost:4000/accounts/register`, formData)
.then(function (response) {
console.log(response)
console.log(response.data)
setServerMessage(response.data)
})
} catch (error) {
console.log(error)
}
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage.message },
})
}
The second component where I am trying to access the state.
const navigate = useNavigate()
let data = useLocation()
console.log(data)
I have tried to log the current state value in the console using this:
useEffect(() => {
console.log(serverMessage)
}, [serverMessage])
I have tried to set the state in useffect like this:
useEffect(() => {
setServerMessage(serverMessage)
}, [serverMessage])
The output I am getting in the browser console is:
Object { pathname: "/session/verifyotp", search: "", hash: "", state: null, key: "n1jhatdj" }
This is the complete code in the page :
import React, { useEffect, useState } from 'react'
import { Box, styled } from '#mui/system'
import { Grid, Button } from '#mui/material'
import { ValidatorForm, TextValidator } from 'react-material-ui-form-validator'
import Typography from '#mui/material/Typography'
import { FormLabel } from '#mui/material'
import Link from '#mui/material/Link'
import axios from 'axios'
import Appbar from '../Appbar'
import Alert from '#mui/material/Alert'
import Snackbar from '#mui/material/Snackbar'
import { useNavigate } from 'react-router-dom'
const FlexBox = styled(Box)(() => ({
display: 'flex',
alignItems: 'center',
}))
const JustifyBox = styled(FlexBox)(() => ({
justifyContent: 'center',
}))
const IMG = styled('img')(() => ({
width: '100%',
}))
const JWTRegister = styled(JustifyBox)(() => ({
background: '#ffffff',
minHeight: '100vh !important',
input: {
background: 'white',
borderRadius: 25,
},
}))
const JwtRegister = (props) => {
const [serverMessage, setServerMessage] = useState('')
const [open, setOpen] = useState(false)
const history = useNavigate()
const [formData, setFormData] = useState({
name: '',
mobile: '',
email: '',
password: '',
})
const handleClick = () => {
setOpen(true)
}
const handleClose = (event, reason) => {
if (reason === 'clickaway') {
return
}
setOpen(false)
}
const { name, mobile, email, password } = formData
const handleChange = (event) => {
setFormData({
...formData,
[event.target.name]: event.target.value,
})
}
const handleFormSubmit = async (event) => {
event.preventDefault()
console.log(formData)
try {
await axios
.post(`http://localhost:4000/accounts/register`, formData)
.then(function (response) {
console.log(response)
console.log(response.data)
const newValue = response.data
setServerMessage(newValue)
})
} catch (error) {
console.log(error)
}
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage },
})
}
useEffect(() => {
console.log(serverMessage)
setServerMessage(serverMessage)
console.log(serverMessage)
}, [serverMessage])
return (
<JWTRegister>
<Grid container>
<Appbar />
<Grid
pt={0}
pl={10}
pr={10}
item
lg={6}
md={6}
sm={6}
xs={12}
sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
>
<Typography
component="h1"
variant="h3"
sx={{ textTransform: 'none', color: '#000' }}
>
Sign up
</Typography>
<Typography component="h1" variant="h5">
Register now to get 100 free credits
</Typography>
{serverMessage ? (
<>
<Alert
variant="filled"
autohideduration={6000}
severity="success"
>
{serverMessage.message}
</Alert>
<Snackbar
open={open}
autoHideDuration={3000}
onClose={handleClose}
>
<Alert
onClose={handleClose}
severity="success"
sx={{ width: '100%' }}
>
{serverMessage.message}
</Alert>
</Snackbar>
</>
) : null}
<ValidatorForm id="Register" onSubmit={handleFormSubmit}>
<Grid container spacing={2}>
<Grid
item
lg={6}
md={6}
sm={12}
xs={12}
sx={{ mt: 2 }}
>
<FormLabel sx={{ color: '#000000' }}>
Name
</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="text"
name="name"
value={name}
autoFocus
onChange={handleChange}
validators={['required']}
errorMessages={['Name field is required']}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
/>
</Grid>
<Grid
item
lg={6}
md={6}
sm={12}
xs={12}
sx={{ mt: 2 }}
>
<FormLabel sx={{ color: '#000000' }}>
Mobile
</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="text"
name="mobile"
value={mobile}
onChange={handleChange}
validators={['required']}
errorMessages={[
'Mobile Number field is required',
]}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
/>
</Grid>
</Grid>
<FormLabel sx={{ color: '#000000' }}>Email</FormLabel>
<TextValidator
sx={{ mb: 3, width: '100%' }}
size="small"
type="email"
name="email"
value={email}
onChange={handleChange}
validators={['required', 'isEmail']}
inputProps={{
style: {
borderRadius: 25,
backgroundColor: 'white',
disableUnderline: true,
},
}}
errorMessages={[
'Email field is required',
'Email is not valid',
]}
/>
<FormLabel sx={{ color: '#000000' }}>
Password
</FormLabel>
<TextValidator
sx={{ mb: '16px', width: '100%' }}
size="small"
name="password"
type="password"
value={password}
onChange={handleChange}
validators={['required']}
errorMessages={['Password field is required']}
inputProps={{
style: {
borderRadius: 25,
disableUnderline: true,
backgroundColor: 'white',
},
}}
/>
<FlexBox pb={2}>
<Button
type="submit"
variant="contained"
sx={{
borderRadius: 25,
textTransform: 'none',
background: '#C7FF80',
color: '#000000',
}}
onClick={handleClick}
>
Verify OTP
</Button>
</FlexBox>
</ValidatorForm>
<Typography
variant="subtitle1"
display="inline"
sx={{
textTransform: 'none',
color: '#000000',
}}
>
Already a member?
<Link
href="/session/signin"
sx={{
textTransform: 'none',
color: '#FFFFFF',
}}
>
Sign in
</Link>
instead.
</Typography>
</Grid>
<Grid
pt={1}
pl={10}
item
lg={6}
md={6}
sm={6}
xs={12}
sx={{ height: '100vh', backgroundColor: '#3E8BFF' }}
>
<Typography pb={3} variant="body">
or sign up with
</Typography>
<Grid
pb={3}
pt={3}
container
alignItems="center"
spacing={2}
>
<Grid item>
<IMG
src="/assets/images/signup-linkedin.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Linkedin
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-google.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Google
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-facebook.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography pb={1} component="h6" variant="h6">
Facebook
</Typography>
</Grid>
</Grid>
<Grid pb={3} container alignItems="center" spacing={2}>
<Grid item>
<IMG
src="/assets/images/signup-email.svg"
height={55}
width={55}
/>
</Grid>
<Grid item>
<Typography component="h6" variant="h6">
Corporate Email ID
</Typography>
<span pb={1} component="h6" variant="h6">
(Use only Business email)
</span>
</Grid>
</Grid>
</Grid>
</Grid>
</JWTRegister>
)
}
export default JwtRegister
No matter what I try I am not able to pass the state to the different component. I have followed this question but does not solve my problem.
How can I access the state value? Why is it coming as null?
I have found the answer to this question. react-router v6 In You need to use your history like this for react-router v6.
This is not the right way to pass state:
history({
pathname: '/session/verifyotp',
state: { serverMessage: serverMessage.message },
})
Correct way to pass state in react-router v6 is the following:
history("/session/verifyotp", {
state: { serverMessage: serverMessage },
});
i recently start to learn react. I made card component using Material UI for react, but this time i'm going to make it with axios and map().
What i expected was, the cards should be in the same row, not vertical.
This is how the cards look when using axios and map()
This the frontend code using React, axios, and map()
import { makeStyles, withStyles } from "#material-ui/styles";
import { BrowserRouter, Route, Routes } from "react-router-dom";
import axios from "axios";
//Material UI
import { Grid } from "#material-ui/core";
import Box from "#mui/material/Box";
import Card from "#mui/material/Card";
import CardActions from "#mui/material/CardActions";
import CardContent from "#mui/material/CardContent";
import Button from "#mui/material/Button";
import Typography from "#mui/material/Typography";
const useStyles = makeStyles({
gridContainer: {
paddingLeft: "40px",
paddingRight: "40px",
},
root: {
minWidth: 200,
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)",
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
});
function Home() {
const classes = useStyles();
const [getData, setGetData] = useState([]);
useEffect(() => {
axios.get("http://127.0.0.1:8080/api/get.php").then((x) => {
setGetData(x.data);
});
}, [getData]);
return (
<div>
{getData.map((x) => {
return (
<Grid
container
spacing={4}
className={classes.gridContainer}
justify="center"
style={{ marginTop: "80px" }}
>
<Grid item xs={12} sm={6} md={4}>
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography className={classes.pos} color="textSecondary">
adjective
</Typography>
<Typography variant="body2" component="p">
well meaning and kindly.
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
</Grid>
</Grid>
);
})}
</div>
);
}
export default Home;
Expected output that i looking for before using map() method
Did i miss some configuration? or styling? grid? container?
<Grid container> should be outside the loop. I would also consider using Material UI v5. Don't forget about key prop for looped items.
<Grid
container
spacing={4}
className={classes.gridContainer}
justifyItems="center"
style={{ marginTop: "80px" }}
>
{getData.map((x, index) => (
<Grid key={index} item xs={12} sm={6} md={4}>
...
</Grid>
)}
</Grid>
Move your Grid Container outside of map function. You have to wrap 3 cards inside the Grid Container
The problem you're having is that you are wrapping each component (using map()) inside its own Grid container. You need to put the container element outside of the map() function so it can work as you expect.
return (
<div>
<Grid
container
spacing={4}
className={classes.gridContainer}
justify="center"
style={{ marginTop: "80px" }}
>
{getData.map((x) => {
return (
<Grid item xs={12} sm={6} md={4}>
<Card className={classes.root} variant="outlined">
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Word of the Day
</Typography>
<Typography className={classes.pos} color="textSecondary">
adjective
</Typography>
<Typography variant="body2" component="p">
well meaning and kindly.
<br />
{'"a benevolent smile"'}
</Typography>
</CardContent>
<CardActions>
<Button size="small">Learn More</Button>
</CardActions>
</Card>
</Grid>
);
})}
</Grid>
</div>
);
I want to render Material UI Elements like MenuItem of a AppBar Conditionally if some conditions are true. In my example menu items should only be rendered for specific users. But it doesnt work like the way it would work with normal html in react.
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
Its rendering this Items all the time anyways and seems to ignoring the conditions.
The full code:
import React from "react";
import { NavLink } from "react-router-dom";
import AuthContext from "../context/auth-context.js";
import AppBar from "#mui/material/AppBar";
import Box from "#mui/material/Box";
import Toolbar from "#mui/material/Toolbar";
import IconButton from "#mui/material/IconButton";
import Typography from "#mui/material/Typography";
import Menu from "#mui/material/Menu";
import MenuIcon from "#mui/icons-material/Menu";
import Container from "#mui/material/Container";
import Avatar from "#mui/material/Avatar";
import Button from "#mui/material/Button";
import Tooltip from "#mui/material/Tooltip";
import MenuItem from "#mui/material/MenuItem";
import ComputerIcon from "#mui/icons-material/Computer";
const ResponsiveAppBar = (props) => {
const pages = ["Conditions", "Winner", "Submission", "Submissions", "Login"];
const settings = ["Profile", "Settings", "Logout"];
const [anchorElNav, setAnchorElNav] = React.useState(null);
const [anchorElUser, setAnchorElUser] = React.useState(null);
const handleOpenNavMenu = (event) => {
setAnchorElNav(event.currentTarget);
};
const handleOpenUserMenu = (event) => {
setAnchorElUser(event.currentTarget);
};
const handleCloseNavMenu = () => {
setAnchorElNav(null);
};
const handleCloseUserMenu = () => {
setAnchorElUser(null);
};
return (
<AuthContext.Consumer>
{(context) => (
<AppBar position="static">
<Container maxWidth="xl">
<Toolbar disableGutters>
<Typography
variant="h6"
noWrap
component="div"
sx={{ mr: 2, display: { xs: "none", md: "flex" } }}
>
<ComputerIcon />
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}>
<IconButton
size="large"
aria-label="account of current user"
aria-controls="menu-appbar"
aria-haspopup="true"
onClick={handleOpenNavMenu}
color="inherit"
>
<MenuIcon />
</IconButton>
<Menu
id="menu-appbar"
anchorEl={anchorElNav}
anchorOrigin={{
vertical: "bottom",
horizontal: "left",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "left",
}}
open={Boolean(anchorElNav)}
onClose={handleCloseNavMenu}
sx={{
display: { xs: "block", md: "none" },
}}
>
{context.token && context.userRole === "USER" && (
<MenuItem key="submission" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submission</Typography>
</MenuItem>
)}
{context.token && context.userRole === "JUDGE" && (
<MenuItem key="submissions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Submissions</Typography>
</MenuItem>
)}
<MenuItem key="conditions" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Conditions</Typography>
</MenuItem>
<MenuItem key="winner" onClick={handleCloseNavMenu}>
<Typography textAlign="center">Winner</Typography>
</MenuItem>
</Menu>
</Box>
<Typography
variant="h6"
noWrap
component="div"
sx={{ flexGrow: 1, display: { xs: "flex", md: "none" } }}
>
LOGO
</Typography>
<Box sx={{ flexGrow: 1, display: { xs: "none", md: "flex" } }}>
{pages.map((page) => (
<Button
key={page}
onClick={handleCloseNavMenu}
sx={{ my: 2, color: "white", display: "block" }}
>
{page}
</Button>
))}
</Box>
<Box sx={{ flexGrow: 0 }}>
<Tooltip title="Open settings">
<IconButton onClick={handleOpenUserMenu} sx={{ p: 0 }}>
<Avatar
alt="Remy Sharp"
src="/static/images/avatar/2.jpg"
/>
</IconButton>
</Tooltip>
<Menu
sx={{ mt: "45px" }}
id="menu-appbar"
anchorEl={anchorElUser}
anchorOrigin={{
vertical: "top",
horizontal: "right",
}}
keepMounted
transformOrigin={{
vertical: "top",
horizontal: "right",
}}
open={Boolean(anchorElUser)}
onClose={handleCloseUserMenu}
>
{settings.map((setting) => (
<MenuItem key={setting} onClick={handleCloseNavMenu}>
<Typography textAlign="center">{setting}</Typography>
</MenuItem>
))}
</Menu>
</Box>
</Toolbar>
</Container>
</AppBar>
)}
</AuthContext.Consumer>
);
};
export default ResponsiveAppBar;
I can not send currentTodos array to Cardhouse I want to send currentTodos array from seach-result.component.jsx to render loop card-house.component.jsx it show error TypeError: currentTodos.map is not a function Cardhouse
C:/Users/pimdo/Desktop/BF-property/src/components/card-house/card-house.component.jsx:45
seach-result.component.jsx
import React from "react";
import Pagination from '#material-ui/lab/Pagination';
import Typography from '#material-ui/core/Typography';
import Cardhouse from '../card-house/card-house.component.jsx'
class Seachresult extends React.Component {
constructor() {
super();
this.state = {
todos: [1,2, 3, 4, 5, 6, 7, 8, 9, 8, 10],
currentPage: 1,
todosPerPage: 6,
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(event, value) {
this.setState({
currentPage: Number(value),
});
}
render() {
const { todos, currentPage, todosPerPage } = this.state;
// Logic for displaying todos
const indexOfLastTodo = currentPage * todosPerPage;
const indexOfFirstTodo = indexOfLastTodo - todosPerPage;
const currentTodos = todos.slice(indexOfFirstTodo, indexOfLastTodo);
// Logic for displaying page numbers
const pageNumbers = [];
for (let i = 1; i <= Math.ceil(todos.length / todosPerPage); i++) {
pageNumbers.push(i);
}
return (
<div>
<Typography>Page: {currentPage}</Typography>
<Cardhouse currentTodos={currentTodos} />
<Pagination count={pageNumbers.length} page={currentPage} size="large" id={currentPage} onChange={this.handleClick} showFirstButton showLastButton />
</div>
);
}
}
export default Seachresult;
card-house.component.jsx
import React from "react";
import CardMedia from "#material-ui/core/CardMedia";
import CardActionArea from "#material-ui/core/CardActionArea";
import Grid from "#material-ui/core/Grid";
import Container from "#material-ui/core/Container";
import Typography from "#material-ui/core/Typography";
import FavoriteIcon from "#material-ui/icons/Favorite";
import HotelIcon from "#material-ui/icons/Hotel";
import BathtubIcon from "#material-ui/icons/Bathtub";
import SquareFootIcon from "#material-ui/icons/SquareFoot";
import RoomIcon from "#material-ui/icons/Room";
import HouseIcon from "#material-ui/icons/House";
import ShareIcon from "#material-ui/icons/Share";
import IconButton from "#material-ui/core/IconButton";
import { Link } from "react-router-dom";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import { makeStyles } from "#material-ui/core/styles";
const useStyles = makeStyles((theme) => ({
cardGrid: {
paddingTop: theme.spacing(8),
paddingBottom: theme.spacing(8),
},
card: {
height: "100%",
display: "flex",
flexDirection: "column",
},
cardMedia: {
paddingTop: "56.25%", // 16:9
},
cardContent: {
flexGrow: 1,
},
}));
export default function Cardhouse(currentTodos) {
const classes = useStyles();
return (
<Container className={classes.cardGrid} maxWidth="lg">
{/* End hero unit */}
<Grid container spacing={3} style={{ marginTop: 15 }}>
{currentTodos.map(currentTodo=> (
<Grid item key={currentTodo} xs={12} sm={6} md={4}>
<Card className={classes.card}>
<CardActionArea component={Link}
to="/property-detail">
<CardMedia
className={classes.cardMedia}
image="https://source.unsplash.com/random"
title="Image title"
/>
<CardContent className={classes.cardContent}>
<Grid container spacing={1}>
<Grid item xs={12}>
<Typography variant="h5">{"บ้านแสนสุข"}</Typography>
</Grid>
<Grid item xs={12}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
<RoomIcon fontSize="small" />
{
"ซอย ลาดพร้าว 101 Khlong Chan, Bang Kapi District, Bangkok, Thailand"
}
</Typography>
</Grid>
<Grid item xs={12}>
<Typography variant="h6" style={{ color: "#26ae61" }}>
{"$"} {"1,900,000"} {"บาท"}
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
<HotelIcon fontSize="large" />
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
<BathtubIcon fontSize="large" />
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
<SquareFootIcon fontSize="large" />
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
<HouseIcon fontSize="large" />
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
{"ห้องนอน 1"}
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
{"น้องน้ำ 1"}
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
{"256 ตารางเมตร"}
</Typography>
</Grid>
<Grid item xs={3}>
<Typography
variant="subtitle2"
style={{ color: "#969696" }}
>
{"บ้านเดี่ยว"}
</Typography>
</Grid>
</Grid>
</CardContent>
</CardActionArea>
<CardActions>
<div style={{ marginLeft: "auto" }}>
<IconButton aria-label="share">
<ShareIcon />
</IconButton>
<IconButton aria-label="add to favorites">
<FavoriteIcon />
</IconButton>
</div>
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
);
}
What you are passing to Cardhouse is actually a props object, not an array. Thus you are getting this error. Ways to resolve this is to change function Cardhouse argument like:
Using props:
export default function Cardhouse( props )
and then change the map() method to:
{props.currentTodos.map(currentTodo=> (
Using Object Destructuring:
Or, you can simply destructure the props object and you will not have to change anything inside the function like:
export default function Cardhouse({ currentTodos })
For more information: Components and Props
This is because the CardHouse component is treating currentTodos as the prop object instead of a prop attribute.
Change:
export default function Cardhouse(currentTodos) {
// code here
}
into:
export default function Cardhouse({ currentTodos }) {
// code here
}
I am putting together a component for my Goal Sharing social media app. This is what I have so far:
I'm trying to position the Avatar component as well as the two typography components beneath the Avatar component within the center of the left section of this Paper component. I have tried doing this by altering marginLeft and marginTop as you can see in the code below, but the issue when I do this is the components in this Goal component jumble on top of each other when I switch over to smaller devices. So, what's the best way to position these components in the center of the left section, and to ensure they remain that way on smaller devices?
This is the parent component file:
import React, { useEffect } from "react";
import Moment from "react-moment";
import PropTypes from "prop-types";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { getGoals } from "../../actions/goal";
import Spinner from "../layout/Spinner";
import Navbar from "../dashboard/Navbar";
import ThumbUpAltIcon from "#material-ui/icons/ThumbUpAlt";
import ThumbDownAltIcon from "#material-ui/icons/ThumbDownAlt";
import ChatIcon from "#material-ui/icons/Chat";
import DeleteIcon from "#material-ui/icons/Delete";
import DoneIcon from "#material-ui/icons/Done";
import {
Typography,
Container,
CssBaseline,
makeStyles,
Grid,
Card,
Avatar,
CardContent,
CardActions
} from "#material-ui/core";
const useStyles = makeStyles(theme => ({
paper: {
marginTop: theme.spacing(8),
display: "flex",
flexDirection: "column",
alignItems: "center"
},
submit: {
margin: theme.spacing(2, 0, 2)
},
form: {
marginTop: theme.spacing(5)
},
cardGrid: {
paddingTop: theme.spacing(4),
paddingBottom: theme.spacing(4)
},
card: {
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center"
},
cardContent: {
flexGrow: 1
},
profileHeader: {
textAlign: "center",
marginBottom: 10
},
avatar: {
width: theme.spacing(10),
height: theme.spacing(10),
marginLeft: "2.5vw",
marginTop: "5vh"
},
name: {
textAlign: "center",
marginLeft: "2vw"
},
goalText: {
marginTop: "5vh",
marginLeft: "3vw"
},
postedOn: {
marginLeft: "2vw"
}
}));
const Goals = ({ getGoals, auth, goal: { goals, user, loading } }) => {
useEffect(() => {
getGoals();
}, [getGoals]);
const classes = useStyles();
return loading ? (
<>
<Navbar />
<Container component="main" maxWidth="xs">
<CssBaseline />
<div className={classes.paper}>
<Spinner />
</div>
</Container>
</>
) : (
<>
<CssBaseline />
<Navbar />
<main>
<Container className={classes.cardGrid} maxWidth="md">
<Typography variant="h2" className={classes.profileHeader}>
Goals
</Typography>
<Grid container spacing={4}>
{goals.map(singleGoal => (
<Grid item key={singleGoal._id} xs={12}>
<Card fullwidth="true" className={classes.card}>
<Grid container spacing={2}>
<Grid item>
<Avatar
className={classes.avatar}
src={singleGoal.avatar}
/>
<Typography variant="subtitle2" className={classes.name}>
{singleGoal.first_name} {singleGoal.last_name}
</Typography>
<Typography
variant="caption"
className={classes.postedOn}
>
Posted on{" "}
<Moment format="MM/DD/YYYY">{singleGoal.date}</Moment>
</Typography>
</Grid>
<Grid item xs={12} sm container>
<Grid item xs container direction="column" spacing={2}>
<Grid item xs>
<Typography
className={classes.goalText}
variant="body1"
gutterBottom
>
{singleGoal.text}
</Typography>
<Typography variant="h5"></Typography>
</Grid>
</Grid>
</Grid>
</Grid>
<CardContent className={classes.cardContent}></CardContent>
<CardActions>
<ThumbUpAltIcon />
<Typography variant="caption">
{singleGoal.likes.length}
</Typography>
<ThumbDownAltIcon />
<Link to={`/goal/${singleGoal.user}`}>
<ChatIcon />
</Link>
<Typography variant="caption">
{singleGoal.comments.length}
</Typography>
{!auth.loading && singleGoal.user === auth.user._id && (
<DoneIcon />
)}
{!auth.loading && singleGoal.user === auth.user._id && (
<DeleteIcon />
)}
</CardActions>
</Card>
</Grid>
))}
</Grid>
</Container>
</main>
</>
);
};
Goals.propTypes = {
getGoals: PropTypes.func.isRequired,
goal: PropTypes.object.isRequired
};
const mapStateToProps = state => ({
goal: state.goal,
auth: state.auth
});
export default connect(mapStateToProps, { getGoals })(Goals);
Try this
card: {
height: "100%",
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center"
},