next.js: Functions are not valid as a React child - reactjs

i trying to use react-countdown for my page and it worked although there are a few notes like react-dom.development.js:88 Warning: Functions are not valid as a React child. This may happen if you return a Component instead of <Component /> from render. Or maybe you meant to call this function rather than return it.
here my full code
import Head from 'next/head'
import React from "react"
import Countdown from "react-countdown"
import {Container, Button, Row, Col, Form, FormControl, InputGroup} from 'react-bootstrap'
class Home extends React.Component {
render() {
// Random component
const Completionist = () => <span>You are good to go!</span>;
const styleCol = {
textAlign: 'center',
color: 'grey',
fontSize: '82px',
fontWeight: 600,
display: 'grid',
fontFamily: 'VERDANABOLD'
}
const styleColSpan = {
color: 'white',
fontSize: '16px'
}
// Renderer callback with condition
const renderer = ({ days, hours, minutes, seconds, completed }) => {
if (completed) {
// Render a complete state
return <Completionist />;
} else {
// Render a countdown
return (
<>
<Col style={styleCol} className={style.clockFrame} lg={3} md={12} sm={12} xs={12}>{days} <span style={styleColSpan}>DAYS</span></Col>
<Col style={styleCol} className={style.clockFrame} lg={3} md={12} sm={12} xs={12}>{hours} <span style={styleColSpan}>HOURS</span></Col>
<Col style={styleCol} className={style.clockFrame} lg={3} md={12} sm={12} xs={12}>{minutes} <span style={styleColSpan}>MINS</span></Col>
<Col style={styleCol} className={style.clockFrame} lg={3} md={12} sm={12} xs={12}>{seconds} <span style={styleColSpan}>SEC</span></Col>
</>
);
}
};
return (
<>
<Container fluid style={{backgroundColor: 'rgba(186, 205, 214, 1)'}} className={style.mainFrame}>
<Row style={{margin:'auto', paddingTop:'40px',
justifyContent:'center'}} className={style.clockFrame}>
{renderer}
<Countdown date={Date.now() + 100000} renderer={renderer} />
</Row>
</Container>
</>
)
}
}
export default Home
in chrome and firefox browsers, the function works.
enter image description here
but in safari return NaN.
enter image description here
anyone can help me please ?

Related

Calculate total call duration In React Component using starttime and endtime props

I need to display the total time of call, the timelineData has already been getting from the props, I have tried to calculate the same using EndDate-StartDate but this logic does not seem to be correct.
import React from 'react'
import { Timeline, Typography, Col, Row } from 'antd'
import { connect } from 'react-redux'
const { Text } = Typography
export class DispositionTimeline extends React.Component {
render() {
return (
<Row className="dispopage">
<Col span={24}>
<Row>
<Col className="timeLineItem" span={24}>
<Row color="transparent">
<Col span={14}></Col>
<Col
style={{
paddingLeft: '8px',
fontWeight: '500'
}}
span={5}
>
Start Time
</Col>
<Col
style={{
paddingLeft: '8px',
fontWeight: '500'
}}
span={5}
>
End Time
</Col>
</Row>
<br />
<Timeline>
{this.props?.timeLineData?.map((value, index) => {
return (
<Timeline.Item>
<Col
className="timelineLabel"
span={14}
style={{
paddingRight: '16px'
}}
>
{value.name}
</Col>
<Col span={5}>
{/* {value.startTime} */}
{value.name !== 'End Call' && value.startTime}
</Col>
<Col span={5}>
{value.name === 'End Call' && value.startTime}
{value.endTime ? ` ${value.endTime}` : ''}
</Col>
</Timeline.Item>
)
})}
</Timeline>
</Col>
</Row>
<Row>
{this.props?.secondAgent?.anotherAgent === 'Primary Agent' ? (
<>
<Col className="timeLineEnd" span={18}>
<Text>Total Call Duration</Text>
</Col>
<Col className="timeLineEnd timeLineEndRight" span={6}>
<Text> {[...this.props?.timeLineData].pop()?.startTime}</Text>
</Col>
</>
) : (
''
)}
</Row>
</Col>
</Row>
)
}
}
export const mapStateToProps = (state, ownProps) => {
return {
timeLineData: ownProps?.timeLineData ? ownProps.timeLineData : state.timeLineData?.timeLineData,
totalDuration: state?.timeLineData?.payload,
secondAgent: state?.secondAgent?.secondAgent
}
}
export default connect(mapStateToProps, null)(DispositionTimeline)
The expression {[...this.props?.timeLineData].pop()?.startTime} is only displaying the startTime of Call. but I want to show the total time, I,e difference between end time and start time

My react Material UI buttons aren't rendering

I've written the same code everywhere but it doesn't render my buttons. It does render but is not visible. The button are present between the logo and the search input.
There aren't any errors nor build fail to debug the problem.
I tried copying and pasting the code from the second too!
import React from "react";
import { Link } from "react-router-dom";
import { Box, Container, ThemeProvider, Input, useScrollTrigger, Slide, AppBar, Toolbar } from '#mui/material'
import { Button } from "#mui/material";
import customTheme from "./Theme"
function HideOnScroll(props) {
const { children, window } = props;
const trigger = useScrollTrigger({
target: window ? window() : undefined,
});
return (
<Slide appear={false} direction="down" in={!trigger}>
{children}
</Slide>
);
}
const ariaLabel = { 'aria-label': 'description' };
function Navigation(props) {
return (
<Container>
<ThemeProvider theme={ customTheme }>
<HideOnScroll>
<AppBar color={"primary"}>
<Toolbar>
<Box m={1} p={1}>
<Link to=""><img src="/static/brand-logo.svg" alt="brand-logo" /></Link>
</Box>
<Box m={1} p={1}>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/">Home</Button>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/blog">Blogs</Button>
<Button variant="outlined" style={{ borderRadius: 20 }} href="/create-blog">Create</Button>
</Box>
<Box m={1} p={1}>
<Input color={"secondary"} placeholder="Can't search :)" inputProps={ariaLabel} />
</Box>
</Toolbar>
</AppBar>
</HideOnScroll>
<Toolbar />
</ThemeProvider>
</Container>
);
}
export default Navigation;
Another button code which works
import React from "react";
import { Grid, Divider, Typography, Button } from "#mui/material";
import InstagramIcon from '#mui/icons-material/Instagram';
import LinkedInIcon from '#mui/icons-material/LinkedIn';
import GitHubIcon from '#mui/icons-material/GitHub';
export default function Home(props) {
return(
<Grid container spacing={4} justifyContent="center" alignItems="center" color={"primary"}>
<Grid item xs={12} sm={6} lg={4}>
<Typography variant="h1" component="div" gutterBottom>A painting of my life.</Typography>
<Button size="large" variant="outlined" style={{ borderRadius: 50, fontSize: 40 }} href="/blog">Peek My Diary</Button>
</Grid>
</Grid>
);
}

Filtering by categories react and bootstrap

i am building an ecommerce website and i'm trying to add category button on the home page so that when you click a specific category, only those items will show. I am using redux to bring all the items to the home screen.
const products = [
{
name: 'Airpods Wireless Bluetooth Headphones',
image: '/images/airpods.jpg',
description:
'Bluetooth technology lets you connect it with compatible devices wirelessly High-quality AAC audio offers immersive listening experience Built-in microphone allows you to take calls while working',
brand: 'Apple',
category: 'Headphones',
price: 89.99,
countInStock: 10,
rating: 4.5,
numReviews: 12,
},
The item structure looks like this.
This is the code I have on the HomeScreen component:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Row, Col, Button, ButtonGroup } from 'react-bootstrap';
import Product from '../components/Product';
import Loader from '../components/Loader';
import Message from '../components/Message';
import { listProducts } from '../actions/productActions';
const HomeScreen = () => {
const dispatch = useDispatch();
const productList = useSelector(state => state.productList);
const { loading, error, products } = productList;
const allCategories = [
'All',
...new Set(products.map(product => product.category)),
];
console.log(allCategories);
useEffect(() => {
dispatch(listProducts());
}, [dispatch]);
return (
<>
<div className="text-center my-4">
<ButtonGroup>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
All
</Button>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
Phones
</Button>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
Headphones
</Button>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
Cameras
</Button>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
Cameras
</Button>
<Button className="btn-color-primary" style={{ margin: '5px' }}>
PlayStation
</Button>
</ButtonGroup>
</div>
{loading ? (
<Loader />
) : error ? (
<Message variant="danger">{error}</Message>
) : (
<Row>
{products.map(product => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>
)}
</>
);
};
export default HomeScreen;
I created a variable that has all the categories from the proeducts mapped plus the 'All' one.What should i add to the Buttons so that when i click on them it would work as wanted?
You can create a state variable that will have the selected category name. Before you render products filter the products which have the category as selected category.
const [selectedCategory, setSelectedCategory] = useState("All");
const handleClick = (category) => setSelectedCategory(category);
Now, for the buttons, you should add an onClick event listener which changes the selectedCategory when it is clicked. for eg
<ButtonGroup>
{
allCategories.map(category => (
<Button onClick={() => handleClick(category)} key={category} className="btn-color-primary" style={{ margin: '5px' }}>
{category}
</Button>)
}
</ButtonGroup>
Now, filter the products if selectedCategory is not "All"
products.filter(product => selectedCategory==="All" || product.category===selectedCategory)
.map(product => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>))
This was your Data -
const products = [
{
name: 'Airpods Wireless Bluetooth Headphones',
image: '/images/airpods.jpg',
description:
'Bluetooth technology lets you connect it with compatible devices wirelessly High-quality AAC audio offers immersive listening experience Built-in microphone allows you to take calls while working',
brand: 'Apple',
category: 'Headphones',
price: 89.99,
countInStock: 10,
rating: 4.5,
numReviews: 12,
},......
Now we can do this to Filter, just change wantedCategory (use it as a state)
const wantedCategory = "Headphones"
const filteredProducts = products.filter(p => p.category === wantedCategory)
then you can map the array to show only filtered items
<Row>
{filteredProducts.map(product => (
<Col key={product._id} sm={12} md={6} lg={4} xl={3}>
<Product product={product} />
</Col>
))}
</Row>

Remove additional whitespace between row items with height (React JS/Material-UI)

I am trying to create a dynamic grid system. I have an dictionary and when any of these values are set to true, the component renders:
const sideBarCategories = [
{ id: "Test", comp: Test, default: false },
{ id: "Y", comp: Y, default: true },
{ id: "X", comp: X, default: false},
{ id: "Z", comp: Z, default: false},
];
So in this case, only the Y widget will be rendered. The render function is wrapped in a grid with direction row as follows:
<Grid
container
direction="row"
alignContent="center"
alignItems="center"
wrap="wrap"
spacing={4}
>
{cardsInGrid.map((card) => {
const Component = sideBarCategories.find(
(cat) => cat.id === card.id
).comp;
return <Component key={card.id} />;
})}
</Grid>
An example of the widget can be seen here:
import React from "react";
import { makeStyles } from "#material-ui/core/styles";
import Card from "#material-ui/core/Card";
import CardActions from "#material-ui/core/CardActions";
import CardContent from "#material-ui/core/CardContent";
import Button from "#material-ui/core/Button";
import Typography from "#material-ui/core/Typography";
import Grid from "#material-ui/core/Grid";
const useStyles = makeStyles({
root: {
minWidth: 275,
},
bullet: {
display: "inline-block",
margin: "0 2px",
transform: "scale(0.8)",
},
title: {
fontSize: 14,
},
pos: {
marginBottom: 12,
},
cardDesign: {
flexGrow: 1,
marginRight: "20px",
marginLeft: "20px",
width: "100%",
},
});
function Y() {
const classes = useStyles();
const bull = <span className={classes.bullet}>•</span>;
return (
<Grid item xs={12} sm={12} md={6} lg={6} xl={6}>
<div className={classes.root}>
<Card className={classes.cardDesign}>
<CardContent>
<Typography
className={classes.title}
color="textSecondary"
gutterBottom
>
Emoji Stats
</Typography>
<Typography variant="h5" component="h2">
be{bull}nev{bull}o{bull}lent
</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>
</div>
</Grid>
);
}
export default Y;
So in the row that I have, I make it so that there's a max of 2 items per row before it goes down and creates a new row (as seen by <Grid item xs={12} sm={12} md={6} lg={6} xl={6}> in the component file above.
The problem I am having is that if any of the components' height is larger than the other item in the same row, the website will account for that by having huge white spaces on either side of the smaller component. (See image below with orange representing whitespace)
I want it so that the components are directly below each other without that extra whitespace (see image below).
Sorry for the long post but any help with this matter would be appreciated.
I think the way you will have to do this is make two separate Grids with the cards mapped to even and odd indexes. Make sure the grids only allow 1 card per row.
<Grid
container
direction="row"
alignContent="center"
alignItems="center"
wrap="wrap"
spacing={4}
>
{cardsInGrid.filter((i, idx) => idx % 2).map((card) => {
const Component = sideBarCategories.find(
(cat) => cat.id === card.id
).comp;
return <Component key={card.id} />;
})}
</Grid>
<Grid
container
direction="row"
alignContent="center"
alignItems="center"
wrap="wrap"
spacing={4}
>
{cardsInGrid.filter((i, idx) => !(idx % 2)).map((card) => {
const Component = sideBarCategories.find(
(cat) => cat.id === card.id
).comp;
return <Component key={card.id} />;
})}
</Grid>
I would then wrap the entire thing in a flex container, with direction set to "row":
.dictionary-container {
display: flex;
flex-direction: row;
}
Hope this helps.

Why does using prop.children on a Rebass Box component output a console.error in Chrome?

I have an app built with NextJS and I have a component composed from the Rebass Library which works, but it gives this warning in the console:
Here is the component:
// Container.js
import { Box } from "rebass"
export const Container = (props) => (
<Box
sx={{
maxWidth: "1240px",
mx: "auto",
px: 3,
}}
>
{props.children}
</Box>
)
And the index component:
import { Container } from "./Container"
const Index = (props) => (
<Container>
<div>Hello, World</div>
</Container>
)
export default Index
How can I get rid of this error message?
So it had nothing to do with the above components but rather another component in another file.
// Navbar.js
import { Flex, Link, Text } from "rebass"
import { Container } from "./Container"
export const Nav = (props) => (
<Container>
<Flex
px={2}
height={70}
color="white"
sx={{ background: `${(props) => props.theme.colors.background}` }}
// Using the line above causes the error
sx={{ background: "background" }} // use this line instead
alignItems="center"
>
<Text p={2} fontWeight="bold">
Company
</Text>
<Flex mx="auto" />
<Link variant="nav" href="#!">
Link
</Link>
</Flex>
</Container>
)
This is the prescribed way to get a themed value into a Rebass component. It didn't work for me so that is why I tried a function.

Resources