I'm trying my app using material-ui lib.
I create a Table and just follow the code in Custom Table Pagination Action, but I got the error like this.
Error I got:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of `TablePaginationActions`.
in TablePaginationActions (created by WithStyles(TablePaginationActions))
in WithStyles(TablePaginationActions) (created by TablePagination)
My DataTables component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import {
ListItem,
TableFooter,
TablePagination,
ListItemText,
Avatar,
Table,
TableBody,
TableCell,
TableHead,
TableRow,
Paper
} from '#material-ui/core';
import TablePaginationActionsWrapped from './TablePaginationActions'
const CustomTableCell = withStyles(theme => ({
body: {
fontSize: 14,
paddingRight: 0,
},
head: {
paddingRight: 0,
}
}))(TableCell);
const CustomTableRow = withStyles(theme => ({
root: {},
}))(TableRow);
const CustomTableHead = withStyles(theme => ({
root: {
padding: '0'
},
}))(TableHead);
const styles = theme => ({
root: {
width: '100%',
marginTop: theme.spacing.unit * 3,
overflowX: 'auto',
borderRadius: '0'
},
table: {
minWidth: 500,
},
tableWrapper: {
overflowX: 'auto',
},
});
class DataTables extends Component {
state = {
data: this.props.reportsList,
page: 0,
rowsPerPage: 10,
}
handleChangePage = (event, page) => {
this.setState({page});
};
handleChangeRowsPerPage = event => {
this.setState({rowsPerPage: event.target.value});
};
render() {
const {classes, reportsList} = this.props;
const {data, rowsPerPage, page} = this.state;
const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);
return (
<Paper className={classes.root}>
<div className={classes.tableWrapper}>
<Table className={classes.table}>
<CustomTableHead>
<CustomTableRow>
<CustomTableCell>ID</CustomTableCell>
<CustomTableCell>Report Title</CustomTableCell>
<CustomTableCell>Author</CustomTableCell>
<CustomTableCell>Date created</CustomTableCell>
</CustomTableRow>
</CustomTableHead>
<TableBody>
{data.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(report => {
return (
<CustomTableRow key={report.id}>
<CustomTableCell>{report.id}</CustomTableCell>
<CustomTableCell component="th" scope="row">
{report.title}
</CustomTableCell>
<CustomTableCell padding="none" component="th" scope="row">
<ListItem>
<Avatar alt="Avatar image" src={report.userId.avatar}/>
<ListItemText>{report.userId.firstName}</ListItemText>
</ListItem>
</CustomTableCell>
<CustomTableCell component="th" scope="row">
{report.date}
</CustomTableCell>
</CustomTableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 48 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
colSpan={3}
count={reportsList.length}
rowsPerPage={this.state.rowsPerPage}
page={this.state.page}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
ActionsComponent={TablePaginationActionsWrapped}
// ActionsComponent={TablePaginationActionsWrapped} If not use this, my app work fine.
/>
</TableRow>
</TableFooter>
</Table>
</div>
</Paper>
);
}
}
DataTables.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(DataTables);
And my TablePaginationActionsWrapped component:
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import IconButton from '#material-ui/core/IconButton';
import { FirstPageIcon, KeyboardArrowLeft, KeyboardArrowRight, LastPageIcon } from '#material-ui/icons'
const actionsStyles = theme => ({
root: {
flexShrink: 0,
color: theme.palette.text.secondary,
marginLeft: theme.spacing.unit * 2.5,
},
});
class TablePaginationActions extends Component {
handleFirstPageButtonClick = event => {
this.props.onChangePage(event, 0);
};
handleBackButtonClick = event => {
this.props.onChangePage(event, this.props.page - 1);
};
handleNextButtonClick = event => {
this.props.onChangePage(event, this.props.page + 1);
};
handleLastPageButtonClick = event => {
this.props.onChangePage(
event,
Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1),
);
};
render() {
const { classes, count, page, rowsPerPage, theme } = this.props;
return (
<div className={classes.root}>
<IconButton
onClick={this.handleFirstPageButtonClick}
disabled={page === 0}
aria-label="First Page"
>
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton
onClick={this.handleBackButtonClick}
disabled={page === 0}
aria-label="Previous Page"
>
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
</IconButton>
<IconButton
onClick={this.handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="Next Page"
>
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</IconButton>
<IconButton
onClick={this.handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="Last Page"
>
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</div>
);
}
}
TablePaginationActions.propTypes = {
classes: PropTypes.object.isRequired,
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired,
};
const TablePaginationActionsWrapped = withStyles(actionsStyles, { withTheme: true })(
TablePaginationActions,
);
export default TablePaginationActionsWrapped;
What did I'm wrong here. please help me.
There is only one issue. You are using wrong name for icon components. It is LastPage and FirstPage not LastPageIcon and FirstPageIcon. Just correct it, and it will work fine.
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { withStyles } from '#material-ui/core/styles'
import IconButton from '#material-ui/core/IconButton'
import { FirstPage, KeyboardArrowLeft, KeyboardArrowRight, LastPage } from '#material-ui/icons'
const actionsStyles = theme => ({
root: {
flexShrink: 0,
color: theme.palette.text.secondary,
marginLeft: theme.spacing.unit * 2.5
}
})
class TablePaginationActions extends Component {
handleFirstPageButtonClick = event => {
this
.props
.onChangePage(event, 0)
}
handleBackButtonClick = event => {
this
.props
.onChangePage(event, this.props.page - 1)
}
handleNextButtonClick = event => {
this
.props
.onChangePage(event, this.props.page + 1)
}
handleLastPageButtonClick = event => {
this
.props
.onChangePage(event, Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1))
}
render() {
const { classes, count, page, rowsPerPage, theme } = this.props
return (
<div className={classes.root}>
<IconButton
onClick={this.handleFirstPageButtonClick}
disabled={page === 0}
aria-label='First Page'>
{theme.direction === 'rtl'
? <LastPage/>
: <FirstPage />}
</IconButton>
<IconButton
onClick={this.handleBackButtonClick}
disabled={page === 0}
aria-label='Previous Page'>
{theme.direction === 'rtl'
? <KeyboardArrowRight />
: <KeyboardArrowLeft />}
</IconButton>
<IconButton
onClick={this.handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label='Next Page'>
{theme.direction === 'rtl'
? <KeyboardArrowLeft />
: <KeyboardArrowRight />}
</IconButton>
<IconButton
onClick={this.handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label='Last Page' />
</div>
)
}
}
TablePaginationActions.propTypes = {
classes: PropTypes.object.isRequired,
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired
}
export default withStyles(actionsStyles, { withTheme: true })(TablePaginationActions)
Try replacing, it should work. You can check icon name from https://material.io/tools/icons/?icon=first_page&style=baseline. You just need to use it by converting it to Capital case. Like icon first_page becomes FirstPage in #material-ui/icons.
Related
I am trying to fetch data with RTK Query in next.js project and everything were fine until I had to fetch some more data from /api/exams endpoint. I have fetched almost everything from that endpoint and i know that's working fine but i still can't fetch some data from it. I'll provide screenshots of all code that's related to it. ok so here is the code where endpoints are:
Then let's continue with exams-response where i define body of endpoint:
Now I will provide code in my custom hook where i import that data from api/exams endpoint query:
And now i will show code of the actual page where i use them and where i think problem may lie also with another file which i will provide after this:
import { memo } from "react"
import { useIntl } from "react-intl"
import Stack from "#mui/material/Stack"
import Typography from "#mui/material/Typography"
import { ExamoTypesEnum } from "src/common/types/examo-types-enum"
import { rolesEnum } from "src/core/roles-enum"
import { useExamAssign } from "src/features/exams/hooks/use-exam-assign"
import { useExams } from "src/features/exams/hooks/use-exams"
import { useStartExam } from "src/features/exams/hooks/use-start-exam"
import { useIsMobile } from "src/helpers/use-is-mobile"
import { useAppSelector } from "src/redux/hooks"
import { ExamoCard } from "src/ui/examo/examo-card"
import { ExamoCardsGrid } from "src/ui/examo/examo-cards-grid"
import { ExamoHeader } from "src/ui/examo/examo-header"
import { CustomizedDialogs } from "src/ui/filter"
import { LoadingSpinner } from "src/ui/loading-spinner"
import { styled } from "src/ui/theme"
import { UnauthenticatedComponent } from "src/ui/unauthenticated"
import { useTags } from "../tags/hooks/use-tags"
import { useActiveExamQuery } from "./api"
const Ourbox = styled.div`
display: flex;
justify-content: space-between;
`
export const ExamsPage = memo(() => {
const isMobile = useIsMobile()
const userRole = useAppSelector((state) => state.auth.role)
const intl = useIntl()
const {
exams,
isLoadingExams,
selectedTags,
setSelectedTags,
checkedFilterTags,
setCheckedFilterTags,
} = useExams()
const { availableTags } = useTags()
const isLoadingAnExam = useAppSelector((state) => state.exam.isLoadingAnExam)
const { startAsync } = useStartExam()
const { data: activeExam, isFetching: isFetchingActiveExam } =
useActiveExamQuery(undefined, { refetchOnMountOrArgChange: 1 })
if (userRole === rolesEnum.None) {
return <UnauthenticatedComponent />
}
return (
<Stack sx={{ paddingX: isMobile ? 3 : "10vw", paddingY: 4 }} gap={4}>
<Ourbox>
<ExamoHeader
header={intl.formatMessage({
id: "exams-header",
defaultMessage: "Choose your exam",
})}
subtitle={intl.formatMessage({
id: "exams-header-subtitle",
defaultMessage:
"Our operators make quizzes and tests to help you upgrade and test your skills.",
})}
/>
<CustomizedDialogs
id="exams-page-filter"
selectedTags={selectedTags}
setSelectedTags={setSelectedTags}
availableTags={availableTags || []}
checkedFilterTags={checkedFilterTags}
setCheckedFilterTags={setCheckedFilterTags}
/>
</Ourbox>
{isLoadingExams && <LoadingSpinner />}
{!isLoadingExams && (!exams || exams.length === 0) && (
<Typography>
{intl.formatMessage({
id: "no-exams-available",
defaultMessage: "No exams available",
})}
</Typography>
)}
{exams && exams.length > 0 && (
<ExamoCardsGrid>
{exams.map((exam) => (
<ExamoCard
key={exam.id}
type={ExamoTypesEnum.EXAM}
useAssign={useExamAssign}
isStartButtonDisabled={
isLoadingAnExam ||
isFetchingActiveExam ||
(activeExam?.exam?.id !== undefined &&
exam.id !== activeExam.exam.id)
}
isResuming={
activeExam?.exam?.id !== undefined &&
exam.id === activeExam.exam.id
}
handleStart={() => startAsync(exam.id)}
isLoading={isLoadingAnExam}
title={exam.title}
duration={exam.duration}
tags={[
...new Set(exam.templates?.flatMap((et) => et.tags) || []),
]}
numberOfQuestions={exam.templates.reduce(
(total, current) => total + current.numberOfQuestions,
0,
)}
deadline-start={exam["deadline-start"]}
deadline-end={exam["deadline-end"]}
i={exam.id}
/>
))}
</ExamoCardsGrid>
)}
</Stack>
)
})
and the last one which is as mapped through in above the code. so it's :
import { memo } from "react"
import * as React from "react"
import { useIntl } from "react-intl"
import AccessTimeIcon from "#mui/icons-material/AccessTime"
import ExpandMoreIcon from "#mui/icons-material/ExpandMore"
import MoreHorizIcon from "#mui/icons-material/MoreHoriz"
import Box from "#mui/material/Box"
import Card from "#mui/material/Card"
import MuiChip from "#mui/material/Chip"
import Collapse from "#mui/material/Collapse"
import Grid from "#mui/material/Grid"
import IconButton, { IconButtonProps } from "#mui/material/IconButton"
import Stack from "#mui/material/Stack"
import { styled } from "#mui/material/styles"
import Typography from "#mui/material/Typography"
import { ExamoTypesEnum } from "src/common/types/examo-types-enum"
import { useAssignType } from "src/common/types/use-assign-type"
import { useAppSelector } from "src/redux/hooks"
import { ExamoAssignTo } from "src/ui/examo/examo-assign-to"
import { ExamoStartDialogBtn } from "src/ui/examo/examo-start-btn"
interface props {
duration: string | null
title: string
tags: string[] | null
numberOfQuestions: number | null
isLoading: boolean
handleStart: () => void
useAssign: useAssignType
isStartButtonDisabled: boolean
isResuming: boolean
type: ExamoTypesEnum
i: number
"deadline-start": string
"deadline-end": string
}
export const ExamoCard = memo(
({
duration,
tags,
title,
isLoading,
numberOfQuestions,
isStartButtonDisabled,
isResuming,
type,
handleStart,
useAssign,
i,
"deadline-end": deadlineEnd,
"deadline-start": deadlineStart,
}: props) => {
console.log(deadlineStart)
const intl = useIntl()
const user = useAppSelector((state) => state.auth)
const durationHours = duration?.split(":")[0]
const durationMinutes = duration?.split(":")[1]
// const [expanded, setExpanded] = React.useState(false)
const [expandedId, setExpandedId] = React.useState(-1)
// const handleExpandClick = () => {
// setExpanded(!expanded)
// }
const handleExpandClick = (i: number) => {
setExpandedId(expandedId === i ? -1 : i)
}
const preventParentOnClick = (event: React.MouseEvent<HTMLElement>) => {
event.stopPropagation()
}
interface ExpandMoreProps extends IconButtonProps {
expand: boolean
}
const ExpandMore = styled((props: ExpandMoreProps) => {
const { expand, ...other } = props
return <IconButton {...other} />
})(({ theme, expand }) => ({
transform: !expand ? "rotate(0deg)" : "rotate(180deg)",
transition: theme.transitions.create("transform", {
duration: theme.transitions.duration.shortest,
}),
}))
return (
<Grid item xs={12} lg={6}>
<Card
onClick={() => handleExpandClick(i)}
aria-expanded={expandedId === i}
elevation={2}
sx={{
padding: "1rem",
height: "100%",
borderRadius: "1rem",
border: "solid 1px var(--palette-grey-400)",
transition: "all 0.1s ease-in-out",
":hover": {
backgroundColor: "var(--palette-grey-100)",
cursor: "pointer",
},
}}
>
<Stack direction="row" justifyContent="space-between">
<Stack
gap={numberOfQuestions ? 1.5 : 6}
sx={{
width: "100%",
}}
>
<Stack
direction="row"
sx={{
justifyContent: "space-between",
}}
>
<Typography
variant="h5"
sx={{ whiteSpace: "pre-wrap", wordBreak: "break-all" }}
>
{title}
</Typography>
<ExpandMore expand={expandedId === i}>
<ExpandMoreIcon />
</ExpandMore>
<Stack
direction="row"
gap={1}
sx={{
justifyContent: "flex-end",
alignItems: "center",
marginTop: "-1.75rem",
}}
>
<AccessTimeIcon />
<Typography
whiteSpace="nowrap"
variant="h6"
>{`${durationHours}h ${durationMinutes}m`}</Typography>
</Stack>
</Stack>
<Collapse in={expandedId === i} timeout="auto" unmountOnExit>
<Stack direction="row" gap={4}>
{numberOfQuestions && (
<Typography variant="h6">
{`${numberOfQuestions} ${intl.formatMessage({
id: "questions",
defaultMessage: "Questions",
})}`}
</Typography>
)}
</Stack>
<Stack
direction="row"
sx={{ flexWrap: "wrap", gap: 1, marginTop: "1rem" }}
>
{tags?.map((t, index) => (
<MuiChip
key={index}
label={t}
variant="filled"
sx={{ fontWeight: "bold" }}
color="secondary"
size="small"
/>
))}
</Stack>
</Collapse>
</Stack>
<Stack
sx={{ marginTop: "-0.5rem" }}
justifyContent="space-between"
alignItems="center"
spacing={user.role === "Operator" ? 0.1 : 1}
>
<MoreHorizIcon sx={{ marginLeft: "2rem" }} />
<Box onClick={preventParentOnClick}>
<Stack sx={{ marginLeft: "1.5rem" }}>
{user.role === "Operator" && (
<ExamoAssignTo useAssign={useAssign} title={title} />
)}
</Stack>
</Box>
<Box onClick={preventParentOnClick}>
<ExamoStartDialogBtn
type={type}
isResuming={isResuming}
handleStart={handleStart}
isLoading={isLoading}
isDisabled={isStartButtonDisabled}
/>
</Box>
</Stack>
</Stack>
</Card>
</Grid>
)
},
)
To sum up guys, I want to also fetch deadlineStart and deadlineEnd but i can't. I think problem is in last file or second to last, because maybe am not defining them properly in interface props in last code. And also i almost forgot to mention that when I try to console.log(deadlineStart) in the last code it says undefined in the browser. Edited Network Pic :
here is screenshot when i console log single exams :
As you can see from the image I have a page where,
the part of the drawer and the dark mode change is found on the parent page.
Where the word Page1 and the input field appear, in the child page.
When the theme is changed, then switched to dark mode, a prop with the darkState state is passed from parent to child.
As you can see from the image if I have an input field in which I am writing, so with some text, then I switch to dark mode or I open the drawer.
The component updates everything, losing all its internal state.
I thought about using useMemo, but I don't know where I should use it.
Can you give me a hand?
Link: https://codesandbox.io/s/competent-sara-dru7w?file=/src/page/Page1.js
App.js
import React from "react";
import PropTypes from "prop-types";
import { Switch, Route, Link, useLocation } from "react-router-dom";
import {
AppBar,
CssBaseline,
Drawer,
Hidden,
IconButton,
List,
ListItem,
ListItemIcon,
ListItemText,
Toolbar,
Chip
} from "#material-ui/core";
import { GTranslate, Menu } from "#material-ui/icons";
import {
makeStyles,
useTheme,
createMuiTheme,
ThemeProvider
} from "#material-ui/core/styles";
import { blue, grey } from "#material-ui/core/colors";
import DarkModeToggle from "react-dark-mode-toggle";
import { Page1, Page2, Error } from "./page";
import "./styles/main.css";
import "./App.css";
const drawerWidth = 240;
function App(props) {
const { wind } = props;
const container = wind !== undefined ? () => wind().document.body : undefined;
const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
const localDark = localStorage.getItem("dark");
const isDark = localDark === null ? prefersDark : localDark === "true";
let location = useLocation();
let pathname = location.pathname.replace("/", "");
if (pathname === "") pathname = "page1";
const [state, setState] = React.useState({
mobileOpen: false,
darkState: isDark,
repo: []
});
const { mobileOpen, darkState } = state;
const useStyles = makeStyles((theme) => ({
root: {
display: "flex"
},
drawer: {
[theme.breakpoints.up("sm")]: {
width: drawerWidth,
flexShrink: 0
}
},
appBar: {
[theme.breakpoints.up("sm")]: {
width: `calc(100% - ${drawerWidth}px)`,
marginLeft: drawerWidth
}
},
menuButton: {
marginRight: theme.spacing(2),
[theme.breakpoints.up("sm")]: {
display: "none"
},
backgroundColor: darkState ? grey[900] : blue[500]
},
// necessary for content to be below app bar
toolbar: theme.mixins.toolbar,
drawerPaper: {
width: drawerWidth,
color: "#ffffff",
backgroundColor: darkState ? grey[900] : blue[500]
},
content: {
flexGrow: 1,
padding: theme.spacing(3)
}
}));
const palletType = darkState ? "dark" : "light";
const mainPrimaryColor = darkState ? grey[900] : blue[500];
const mainSecondaryColor = darkState ? grey[800] : blue[300];
const darkTheme = createMuiTheme({
palette: {
type: palletType,
primary: {
main: mainPrimaryColor
},
secondary: {
main: mainSecondaryColor
}
}
});
const classes = useStyles();
const theme = useTheme();
const handleDrawerToggle = () =>
setState((prev) => ({ ...prev, mobileOpen: !mobileOpen }));
const changePage = (page) => setState((prev) => ({ ...prev, page }));
const handleThemeChange = React.useCallback(() => {
localStorage.setItem("dark", !darkState);
setState((prev) => ({ ...prev, darkState: !prev.darkState }));
}, []);
const menu = [
{ title: "Page1", path: "page1", icon: <GTranslate /> },
{ title: "Page2", path: "page2", icon: <GTranslate /> }
];
const routeObj = [
{ path: "/", obj: <Page1 darkState={darkState} /> },
{ path: "page1", obj: <Page1 darkState={darkState} /> },
{ path: "page2", obj: <Page2 darkState={darkState} /> }
];
const drawer = (
<div className="mt-32">
<div className={classes.toolbar} />
<List>
{menu.map(({ title, path, icon, badge }, index) => (
<Link to={`/${path}`} key={title}>
<ListItem button key={title} onClick={() => changePage(path)}>
<ListItemIcon
style={{ color: path === pathname ? "#ffffff" : "#ffffff80" }}
>
{icon}
</ListItemIcon>
<ListItemText
primary={<span className="font-bold">{title}</span>}
style={{ color: path === pathname ? "#ffffff" : "#ffffff80" }}
/>
{badge && (
<Chip
label={badge}
size="small"
color="secondary"
className="font-bold"
style={{ color: "#ffffff" }}
/>
)}
</ListItem>
</Link>
))}
</List>
</div>
);
return (
<ThemeProvider theme={darkTheme}>
<div className={classes.root}>
<CssBaseline />
<AppBar
position="fixed"
className={classes.appBar}
style={{
backgroundColor: darkState ? "#303030" : grey[50],
boxShadow: "none"
}}
>
<Toolbar className={"shadow-none"}>
<IconButton
color="inherit"
aria-label="open drawer"
edge="start"
onClick={handleDrawerToggle}
className={classes.menuButton}
>
<Menu />
</IconButton>
<div className="ml-auto text-right flex">
<DarkModeToggle
onChange={handleThemeChange}
checked={darkState}
size={60}
/>
</div>
</Toolbar>
</AppBar>
<nav className={classes.drawer} aria-label="mailbox folders">
{/* The implementation can be swapped with js to avoid SEO duplication of links. */}
<Hidden smUp implementation="css">
<Drawer
container={container}
variant="temporary"
anchor={theme.direction === "rtl" ? "right" : "left"}
open={mobileOpen}
onClose={handleDrawerToggle}
classes={{
paper: classes.drawerPaper
}}
ModalProps={{
keepMounted: true // Better open performance on mobile.
}}
>
{drawer}
</Drawer>
</Hidden>
<Hidden xsDown implementation="css">
<Drawer
classes={{
paper: classes.drawerPaper
}}
variant="permanent"
open
>
{drawer}
</Drawer>
</Hidden>
</nav>
<main className={classes.content}>
<div className={classes.toolbar} />
<Switch>
{routeObj.map(({ path, obj }, key) => (
<Route exact path={`/${path}`} component={() => obj} key={key} />
))}
<Route component={() => <Error darkState={darkState} />} />
</Switch>
</main>
</div>
</ThemeProvider>
);
}
App.propTypes = {
/**
* Injected by the documentation to work in an iframe.
* You won't need it on your project.
*/
wind: PropTypes.func
};
export default App;
Page1.js
import React, { useState, useEffect } from "react";
import { TextField, makeStyles } from "#material-ui/core";
import { className } from "../function";
import "../styles/main.css";
export default function Page1({ darkState }) {
const useStyles = makeStyles((theme) => ({
title: {
color: darkState ? "#ffffff" : "#343a40",
textShadow: `3px 3px 2px ${
darkState ? "rgba(0, 0, 0, 1)" : "rgba(150, 150, 150, 1)"
}`
},
button: {
margin: theme.spacing(1)
}
}));
const classes = useStyles();
const [state, setState] = useState({
name: ""
});
const { name } = state;
useEffect(() => {
console.log(darkState, state);
}, []);
useEffect(() => {
console.log("darkState", darkState, state);
}, [darkState]);
const onChange = ({ target: { value } }, name) => {
setState((prev) => ({ ...prev, [name]: value }));
};
console.log(state);
return (
<>
<h1 className={className(classes.title, "text-6xl font-bold hp")}>
Page
<span className="text-primary">1</span>
</h1>
<div
style={{
width: "50%",
minHeight: "600px"
}}
>
<div style={{ paddingBottom: 15 }}>
<TextField
fullWidth
id="outlined-basic"
label={"Name"}
variant="outlined"
size="small"
value={name}
onChange={(value) => onChange(value, "name")}
/>
</div>
</div>
</>
);
}
How can I send the value of the checkbox to the checkout.js page? This is the PaymentForm page. I tried my best but it's not working correctly. Basically, I want to use the PaymentForm fields in checkout.js page because my submit button is there.
PaymentForm.js
import React from 'react';
import Typography from '#material-ui/core/Typography';
import Grid from '#material-ui/core/Grid';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import { createStyles } from '#material-ui/core/styles';
import StripeCheckout from 'react-stripe-checkout'
import 'react-toastify/dist/ReactToastify.css';
const styles = createStyles({
formControlLabel: {
fontSize: '1.5rem',
'& label': { fontSize: '5rem' }
}
});
const handleToken = (token) => {
console.log(token);
}
const PaymentForm = ({ PaymentForm, changePaymentForm }) => {
const [state, setState] = React.useState({
checkedA: false,
});
const handleChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
};
return (
<React.Fragment>
<Typography variant="h4" gutterBottom>
Payment method
</Typography><br />
<Grid container spacing={3}>
<Grid item xs={12}>
<FormControlLabel
control={<Checkbox checked={state.checkedA} onChange={handleChange} name="checkedA"/>}
label={<Typography style={styles.formControlLabel}>Cash on delivery</Typography>}
/>
</Grid>
<Grid item xs={12}>
<StripeCheckout
stripeKey="pk_test_51I9XPQAesAg2GfzQyVB7VgP0IbmWwgcfeFJSuCpB2kbNu60AFTbFhC7dxwje8YF4w2ILMJ6o2InB9ENczpd4dCSa00e09XoDbw"
token={handleToken}
amount={2 * 100}
name="All Products"
/>
</Grid>
</Grid>
</React.Fragment>
);
};
export default PaymentForm;
Checkout.js
import React from 'react';
import { makeStyles } from '#material-ui/core/styles';
import CssBaseline from '#material-ui/core/CssBaseline';
import AppBar from '#material-ui/core/AppBar';
import Toolbar from '#material-ui/core/Toolbar';
import Paper from '#material-ui/core/Paper';
import Stepper from '#material-ui/core/Stepper';
import Step from '#material-ui/core/Step';
import StepLabel from '#material-ui/core/StepLabel';
import Button from '#material-ui/core/Button';
import Link from '#material-ui/core/Link';
import Typography from '#material-ui/core/Typography';
import axios from '../../axios-orders';
import AddressForm from './CheckoutForm';
import PaymentForm from './PaymentForm';
import Review from './Review';
const useStyles = makeStyles((theme) => ({
appBar: {
position: 'relative',
},
layout: {
width: 'auto',
marginLeft: theme.spacing(2),
marginRight: theme.spacing(2),
[theme.breakpoints.up(1000 + theme.spacing(2) * 2)]: {
width: 1100,
marginLeft: 'auto',
marginRight: 'auto',
},
},
paper: {
marginTop: theme.spacing(3),
marginBottom: theme.spacing(3),
padding: theme.spacing(2),
[theme.breakpoints.up(700 + theme.spacing(3) * 2)]: {
marginTop: theme.spacing(6),
marginBottom: theme.spacing(6),
padding: theme.spacing(3),
backgroundColor: 'rgb(248, 246, 244)',
},
},
stepper: {
padding: theme.spacing(5, 0, 5),
fontWeight: 'bold',
backgroundColor: 'rgb(248, 246, 244)',
},
buttons: {
display: 'flex',
justifyContent: 'flex-end',
},
button: {
marginTop: theme.spacing(3),
marginLeft: theme.spacing(1),
border: "none"
},
}));
const steps = ['Shipping address', 'Payment details', 'Review your order'];
function Copyright() {
return (
<Typography variant="body2" color="textSecondary" align="center">
{'Copyright © '}
<Link color="inherit" href="https://material-ui.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
function getStepContent(step, formValues = null, changeFormValue = null, paymentValues = null, changePaymentValue = null) {
switch (step) {
case 0:
return <AddressForm addressValues={formValues} changeAddressValue={changeFormValue} />;
case 1:
return <PaymentForm PaymentForm={paymentValues} changePaymentForm={changePaymentValue}/>;
case 2:
return <Review />;
default:
throw new Error('Unknown step');
}
}
export default function Checkout(props) {
const classes = useStyles();
const [addressFormValues, setAddressFormValues] = React.useState({});
const [paymentFormValues, setPaymentFormValues] = React.useState({});
const [paymentFormNewValues, setPaymentFormNewValues] = React.useState({});
const [activeStep, setActiveStep] = React.useState(0);
if(paymentFormValues === true){
setPaymentFormNewValues('Cash')
}
if(paymentFormValues === false){
setPaymentFormNewValues('Online')
}
console.log('[paymentFormNewValues: ]', paymentFormNewValues)
console.log('[paymentFormValues: ]', paymentFormValues)
const handleNext = () => {
setActiveStep(activeStep + 1);
axios.post('/UserPortal/CartItems/checkout_details_check.php', {
customer_id: localStorage.getItem('Id'),
})
.then((response) => {
if(response.data === null)
{
axios.post('/UserPortal/CartItems/checkout_details.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state
})
.then((response) => {
console.log(response.data);
})
}
else{
axios.post('/UserPortal/CartItems/checkout_details_update.php', {
customer_id: localStorage.getItem('Id'),
firstname: addressFormValues.firstname,
lastname: addressFormValues.lastname,
address: addressFormValues.address,
city: addressFormValues.city,
state: addressFormValues.state,
payment_method: paymentFormNewValues
})
.then((response) => {
console.log(response.data);
})
}
})
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
const changeAddressFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setAddressFormValues(values);
};
const changePaymentFormValue = (key, value) => {
let values = { ...addressFormValues };
values[key] = value;
setPaymentFormValues(values);
};
return (
<React.Fragment>
<CssBaseline />
<AppBar position="absolute" color="default" className={classes.appBar}></AppBar>
<main className={classes.layout}>
<Paper className={classes.paper}>
<Typography component="h1" variant="h3" align="center">
Checkout
</Typography>
<Stepper activeStep={activeStep} className={classes.stepper}>
{steps.map((label) => (
<Step key={label}>
<StepLabel><Typography component="h1" variant="h5" align="center">
{label} </Typography></StepLabel>
</Step>
))}
</Stepper>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your order.
</Typography>
<Typography variant="subtitle1">
Your order number is #2001539. We have emailed your order
confirmation, and will
send you an update when your order has shipped.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{activeStep === 0 ? getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
{ <div className={classes.buttons}>
{ activeStep !== 0 && (
<Button variant="contained" style={{outline: 'none'}}
className={classes.button}
onClick={handleBack}
>
Back
</Button>
)}
<Button style={{outline: 'none'}}
variant="contained"
color="secondary"
onClick={handleNext}
className={classes.button}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</div> }
</React.Fragment>
)}
</React.Fragment>
</Paper>
<Copyright />
</main>
</React.Fragment>
);
}
It seems you have checked the activeStep wrong.
Maybe the right code must be like the following:
<React.Fragment>
{activeStep !== 0 ?getStepContent(activeStep, addressFormValues, changeAddressFormValue , paymentFormValues, changePaymentFormValue) : getStepContent(activeStep)}
Do you ever consider using Context API?
React Context API
But also you can use create a checkboxValue with useState in Checkout.js and pass setCheckBoxValue to PaymentForm in getStepContent as prop. When checkbox checked trigger setCheckBoxValue and it will trigger parent component's state (Checkbox).
I am trying to convert the setState into useState.
so I followed the below article and converted partially
https://medium.com/javascript-in-plain-english/state-management-with-react-hooks-no-redux-or-context-api-8b3035ceecf8- but not sure how to convert the props
but its not rendering the values.
so I debugged and put console inside useEffect.
I am getting undefind at this line, am I using useState wrongly
useEffect(() => {
console.log("useEffect setspHeight--->", setspHeight);
can you let me know how to fix it and do I need to make any other changes for react hooks
class component code
import React, { Fragment, useState, Component } from 'react';
import styles from './styles';
import { withStyles } from '#material-ui/core/styles';
import classnames from 'classnames';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import IconButton from '#material-ui/core/IconButton';
import Button from '#material-ui/core/Button';
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
import Checkbox from '#material-ui/core/Checkbox';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import dataStyles from '../../../../styles.css';
function TabContainer(props) {
return (
<Typography component="div" style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
const radioValues = [
{
label: 'Select All Providers for This Category',
value: 'PRO',
},
];
class SportsExpansion extends Component {
state = {
value: 0,
spHeight: [],
spLength: '',
};
componentDidMount() {
this.setState({ spHeight: this.props.spHeight });
if (
this.props.spHeight.filter(
check => check.spWeight === 'One'
).length > 0
) {
this.setState({ value: 0 });
} else if (
this.props.spHeight.filter(
check => check.spWeight === 'Two'
).length > 0
) {
this.setState({ value: 1 });
}
}
handleChange = (event, value) => {
console.log('handleChange -value', value);
this.setState({ value });
};
handleSportsRadioValueChange = (category, value) => {
console.log('handleSportsRadioValueChange -category', category);
console.log('handleSportsRadioValueChange -value', value);
this.setState({ spLength: value });
};
render() {
const { classes, data } = this.props;
let udVal = '';
let starVal = '';
udVal = data.udVals ? data.udVals[0].number : '';
starVal = data.starVals ? data.starVals[0].number : '';
const { canEdit, value } = this.state;
const { spHeight } = this.state;
return (
<div>
<AppBar
className={classes.benchmarkTabHeader}
position="static"
color="default"
>
<Tabs
onChange={this.handleChange}
variant="scrollable"
scrollButtons="on"
indicatorColor="primary"
textColor="primary"
style={{ display: 'block' }}
classes={{
indicator: classes.tabsIndicator,
scrollButtons: classes.MuiPrivateTabScrollButton,
}}
>
<Tab
style={{
display:
this.state.spHeight.filter(
check =>
check.spWeight === 'One'
).length === 0
? 'none'
: '',
color: value == 0 ? '#1976D2' : '#66696C',
}}
label={`Groups (${
this.state.spHeight.filter(
check =>
check.spWeight === 'One'
).length
})`}
icon={
<FontAwesomeIcon style={{ display: 'block' }} />
}
classes={{
root: classes.tabRoot,
selected: classes.tabSelected,
wrapper: classes.alignment,
}}
/>
<Tab
style={{
display:
this.state.spHeight.filter(
check =>
check.spWeight ===
'Two'
).length === 0
? 'none'
: '',
color: value == 1 ? '#1976D2' : '#66696C',
}}
label={`Two (${
this.state.spHeight.filter(
check =>
check.spWeight ===
'Two'
).length
})`}
icon={
<FontAwesomeIcon style={{ display: 'block' }} />
}
classes={{
root: classes.tabRoot,
selected: classes.tabSelected,
wrapper: classes.alignment,
}}
/>
</Tabs>
</AppBar>
{value === 0 && (
<TabContainer>
<div>
{' '}
<FormControl
component="fieldset"
className={classes.formControl}
>
<FormLabel component="legend" />
<RadioGroup
aria-label="Gender"
name="gender1"
className={classes.one}
value={this.state.spLength}
onChange={e => {
this.setState({
spLength: e.target.value,
});
}}
>
{this.state.spHeight
.filter(
check =>
check.spWeight ===
'One'
)
.map((radio, radioIndex) => {
return (
<FormControlLabel
key={radioIndex}
value={radio.value}
control={<Radio />}
label={radio.label}
classes={{
label:
classes.checkboxLabel,
}}
/>
);
})}
)}
</RadioGroup>
</FormControl>
<div className="tiger-button-container">
<Button
variant="outlined"
color="primary"
size="small"
className="tiger-button-upload"
>
ghsd jkjkjk
</Button>
</div>
<Drawer
style={{ width: 500 }}
anchor="right"
open={this.state.right}
>
<div tabIndex={0} role="button"></div>
</Drawer>
</div>
</TabContainer>
)}
{value === 1 && (
<TabContainer>
<div>
<div>
<FormControl
component="fieldset"
className={classes.formControl}
>
<RadioGroup
aria-label="Gender"
name="gender1"
className={classes.one}
value={this.state.spLength}
onChange={e => {
this.setState({
spLength:
e.target.value,
});
}}
>
{this.state.spHeight
.filter(
check =>
check.spWeight ===
'Two'
)
.map((radio, radioIndex) => {
return (
<FormControlLabel
key={radioIndex}
value={radio.label}
control={<Radio />}
label={radio.label}
classes={{
label:
classes.checkboxLabel,
}}
/>
);
})}
</RadioGroup>
</FormControl>
<div className="tiger-button-container">
<Button
variant="outlined"
color="primary"
size="small"
className="tiger-button-upload"
>
ghsd jkjkjk
</Button>
</div>
</div>
</div>
</TabContainer>
)}
</div>
);
}
}
export default withStyles(styles)(SportsExpansion);
////////////////////////////////////////////////
functional component code
import React, { Fragment, useState, useEffect, Component } from 'react';
import styles from './styles';
import { withStyles } from '#material-ui/core/styles';
import classnames from 'classnames';
import ExpandMoreIcon from '#material-ui/icons/ExpandMore';
import IconButton from '#material-ui/core/IconButton';
import Button from '#material-ui/core/Button';
import ExpansionPanel from '#material-ui/core/ExpansionPanel';
import ExpansionPanelSummary from '#material-ui/core/ExpansionPanelSummary';
import ExpansionPanelDetails from '#material-ui/core/ExpansionPanelDetails';
import Typography from '#material-ui/core/Typography';
import Drawer from '#material-ui/core/Drawer';
import AppBar from '#material-ui/core/AppBar';
import Tabs from '#material-ui/core/Tabs';
import Tab from '#material-ui/core/Tab';
import { FontAwesomeIcon } from '#fortawesome/react-fontawesome';
import Radio from '#material-ui/core/Radio';
import RadioGroup from '#material-ui/core/RadioGroup';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import FormControl from '#material-ui/core/FormControl';
import FormLabel from '#material-ui/core/FormLabel';
import Checkbox from '#material-ui/core/Checkbox';
import { MuiThemeProvider, createMuiTheme } from '#material-ui/core/styles';
import dataStyles from '../../../../styles.css';
function TabContainer(props) {
return (
<Typography component="div" style={{ padding: 8 * 3 }}>
{props.children}
</Typography>
);
}
const radioValues = [
{
label: 'Select All Providers for This Category',
value: 'PRO',
},
];
//class SportsExpansion extends Component {
const SportsExpansion = (props) => {
const [value, setValue] = useState(0);
const [spHeight, setspHeight] = useState([]);
const [spLength, setspLength] = useState('');
// const { classes, data } = this.props;
const { classes, data } = props;
let udVal = '';
let starVal = '';
udVal = data.udVals ? data.udVals[0].number : '';
starVal = data.starVals ? data.starVals[0].number : '';
// const { canEdit, value } = this.state;
// const { spHeight } = this.state;
useEffect(() => {
// code to run on component mount
console.log("useEffect setspHeight--->", setspHeight);
//this.setState({ spHeight: this.props.spHeight });
setspHeight(spHeight);
if (
spHeight.filter(
check => check.spWeight === 'One'
).length > 0
) {
useState({ value: 0 });
} else if (
spHeight.filter(
check => check.spWeight === 'Two'
).length > 0
) {
useState({ value: 1 });
}
}, [])
//handleChange = (event, value) => {
const handleChange = (event, value) => {
console.log('handleChange -value', value);
useState({ value });
};
// handleSportsRadioValueChange = (category, value) => {
const handleSportsRadioValueChange = (category, value) => {
console.log('handleSportsRadioValueChange -category', category);
console.log('handleSportsRadioValueChange -value', value);
useState({ spLength: value });
};
return (
<div>
<AppBar
className={classes.benchmarkTabHeader}
position="static"
color="default"
>
<Tabs
onChange={this.handleChange}
variant="scrollable"
scrollButtons="on"
indicatorColor="primary"
textColor="primary"
style={{ display: 'block' }}
classes={{
indicator: classes.tabsIndicator,
scrollButtons: classes.MuiPrivateTabScrollButton,
}}
>
<Tab
style={{
display:
//this.state.spHeight.filter(
spHeight.filter(
check =>
check.spWeight === 'One'
).length === 0
? 'none'
: '',
color: value == 0 ? '#1976D2' : '#66696C',
}}
label={`Groups (${
//this.state.spHeight.filter(
spHeight.filter(
check =>
check.spWeight === 'One'
).length
})`}
icon={
<FontAwesomeIcon style={{ display: 'block' }} />
}
classes={{
root: classes.tabRoot,
selected: classes.tabSelected,
wrapper: classes.alignment,
}}
/>
<Tab
style={{
display:
//this.state.spHeight.filter(
spHeight.filter(
check =>
check.spWeight ===
'Two'
).length === 0
? 'none'
: '',
color: value == 1 ? '#1976D2' : '#66696C',
}}
label={`Two (${
//this.state.spHeight.filter(
spHeight.filter(
check =>
check.spWeight ===
'Two'
).length
})`}
icon={
<FontAwesomeIcon style={{ display: 'block' }} />
}
classes={{
root: classes.tabRoot,
selected: classes.tabSelected,
wrapper: classes.alignment,
}}
/>
</Tabs>
</AppBar>
{value === 0 && (
<TabContainer>
<div>
{' '}
<FormControl
component="fieldset"
className={classes.formControl}
>
<FormLabel component="legend" />
<RadioGroup
aria-label="Gender"
name="gender1"
className={classes.one}
value={//this.state.spLength
spLength}
onChange={e => {
useState({
spLength: e.target.value,
});
}}
>
{//this.state.spHeight
spHeight
.filter(
check =>
check.spWeight ===
'One'
)
.map((radio, radioIndex) => {
return (
<FormControlLabel
key={radioIndex}
value={radio.value}
control={<Radio />}
label={radio.label}
classes={{
label:
classes.checkboxLabel,
}}
/>
);
})}
)}
</RadioGroup>
</FormControl>
<div className="tiger-button-container">
<Button
variant="outlined"
color="primary"
size="small"
className="tiger-button-upload"
>
ghsd jkjkjk
</Button>
</div>
{/*<Drawer
style={{ width: 500 }}
anchor="right"
open={
//this.state.right
right}
>
<div tabIndex={0} role="button"></div>
</Drawer>*/}
</div>
</TabContainer>
)}
{value === 1 && (
<TabContainer>
<div>
<div>
<FormControl
component="fieldset"
className={classes.formControl}
>
<RadioGroup
aria-label="Gender"
name="gender1"
className={classes.one}
value={//this.state.spLength
spLength}
onChange={e => {
useState({
spLength:
e.target.value,
});
}}
>
{//this.state.spHeight
spHeight
.filter(
check =>
check.spWeight ===
'Two'
)
.map((radio, radioIndex) => {
return (
<FormControlLabel
key={radioIndex}
value={radio.label}
control={<Radio />}
label={radio.label}
classes={{
label:
classes.checkboxLabel,
}}
/>
);
})}
</RadioGroup>
</FormControl>
<div className="tiger-button-container">
<Button
variant="outlined"
color="primary"
size="small"
className="tiger-button-upload"
>
ghsd jkjkjk
</Button>
</div>
</div>
</div>
</TabContainer>
)}
</div>
);
}
export default withStyles(styles)(SportsExpansion);
You have to replace where you call useState({ value: 1 }); to setValue(value)
You are using useState wrong. useState replaces the state object. The first value in the array is the value you can call in your component. The second value in the array replaces this.setState and sets the value of the state instance. So to use the useState hook if you had the following:
const [value, setValue] = useState(0);
you would use value in your component to reference this state instance. And you would use setValue to set the value of this state instance. So to set value to 2 you would do setValue(2).
I m using Material UI and following this https://material-ui.com/demos/tables/ sample.
When i try to do sample for Custom Table Pagination Action it's not working. It's returning inherits.js:5 Uncaught TypeError: Super expression must either be null or a function error.
I narrow down to issue, when i add the below import i could see the above error.
import TablePagination from '#material-ui/core/TablePagination';
Please find the code below and suggest me to move on.
import React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Table from '#material-ui/core/Table';
import TableBody from '#material-ui/core/TableBody';
import TableCell from '#material-ui/core/TableCell';
import TableFooter from '#material-ui/core/TableFooter';
import TablePagination from '#material-ui/core/TablePagination';
import TableRow from '#material-ui/core/TableRow';
import Paper from '#material-ui/core/Paper';
import IconButton from '#material-ui/core/IconButton';
import FirstPageIcon from '#material-ui/icons/FirstPage';
import KeyboardArrowLeft from '#material-ui/icons/KeyboardArrowLeft';
import KeyboardArrowRight from '#material-ui/icons/KeyboardArrowRight';
import LastPageIcon from '#material-ui/icons/LastPage';
const actionsStyles = theme => ({
root: {
flexShrink: 0,
color: theme.palette.text.secondary,
marginLeft: theme.spacing.unit * 2.5,
},
});
class TablePaginationActions extends React.Component {
handleFirstPageButtonClick = event => {
this.props.onChangePage(event, 0);
};
handleBackButtonClick = event => {
this.props.onChangePage(event, this.props.page - 1);
};
handleNextButtonClick = event => {
this.props.onChangePage(event, this.props.page + 1);
};
handleLastPageButtonClick = event => {
this.props.onChangePage(
event,
Math.max(0, Math.ceil(this.props.count / this.props.rowsPerPage) - 1),
);
};
render() {
const { classes, count, page, rowsPerPage, theme } = this.props;
return (
<div className={classes.root}>
<IconButton
onClick={this.handleFirstPageButtonClick}
disabled={page === 0}
aria-label="First Page"
>
{theme.direction === 'rtl' ? <LastPageIcon /> : <FirstPageIcon />}
</IconButton>
<IconButton
onClick={this.handleBackButtonClick}
disabled={page === 0}
aria-label="Previous Page"
>
{theme.direction === 'rtl' ? <KeyboardArrowRight /> : <KeyboardArrowLeft />}
</IconButton>
<IconButton
onClick={this.handleNextButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="Next Page"
>
{theme.direction === 'rtl' ? <KeyboardArrowLeft /> : <KeyboardArrowRight />}
</IconButton>
<IconButton
onClick={this.handleLastPageButtonClick}
disabled={page >= Math.ceil(count / rowsPerPage) - 1}
aria-label="Last Page"
>
{theme.direction === 'rtl' ? <FirstPageIcon /> : <LastPageIcon />}
</IconButton>
</div>
);
}
}
TablePaginationActions.propTypes = {
classes: PropTypes.object.isRequired,
count: PropTypes.number.isRequired,
onChangePage: PropTypes.func.isRequired,
page: PropTypes.number.isRequired,
rowsPerPage: PropTypes.number.isRequired,
theme: PropTypes.object.isRequired,
};
const TablePaginationActionsWrapped = withStyles(actionsStyles, { withTheme: true })(
TablePaginationActions,
);
let counter = 0;
function createData(name, calories, fat) {
counter += 1;
return { id: counter, name, calories, fat };
}
const styles = theme => ({
root: {
width: '100%',
marginTop: theme.spacing.unit * 3,
},
table: {
minWidth: 500,
},
tableWrapper: {
overflowX: 'auto',
},
});
class CustomPaginationActionsTable extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [
createData('Cupcake', 305, 3.7),
createData('Donut', 452, 25.0),
createData('Eclair', 262, 16.0),
createData('Frozen yoghurt', 159, 6.0),
createData('Gingerbread', 356, 16.0),
createData('Honeycomb', 408, 3.2),
createData('Ice cream sandwich', 237, 9.0),
createData('Jelly Bean', 375, 0.0),
createData('KitKat', 518, 26.0),
createData('Lollipop', 392, 0.2),
createData('Marshmallow', 318, 0),
createData('Nougat', 360, 19.0),
createData('Oreo', 437, 18.0),
].sort((a, b) => (a.calories < b.calories ? -1 : 1)),
page: 0,
rowsPerPage: 5,
};
}
handleChangePage = (event, page) => {
this.setState({ page });
};
handleChangeRowsPerPage = event => {
this.setState({ rowsPerPage: event.target.value });
};
render() {
const { classes } = this.props;
const { data, rowsPerPage, page } = this.state;
const emptyRows = rowsPerPage - Math.min(rowsPerPage, data.length - page * rowsPerPage);
return (
<Paper className={classes.root}>
<div className={classes.tableWrapper}>
<Table className={classes.table}>
<TableBody>
{data.slice(page * rowsPerPage, page * rowsPerPage + rowsPerPage).map(n => {
return (
<TableRow key={n.id}>
<TableCell component="th" scope="row">
{n.name}
</TableCell>
<TableCell numeric>{n.calories}</TableCell>
<TableCell numeric>{n.fat}</TableCell>
</TableRow>
);
})}
{emptyRows > 0 && (
<TableRow style={{ height: 48 * emptyRows }}>
<TableCell colSpan={6} />
</TableRow>
)}
</TableBody>
<TableFooter>
<TableRow>
<TablePagination
colSpan={3}
count={data.length}
rowsPerPage={rowsPerPage}
page={page}
onChangePage={this.handleChangePage}
onChangeRowsPerPage={this.handleChangeRowsPerPage}
ActionsComponent={TablePaginationActionsWrapped}
/>
</TableRow>
</TableFooter>
</Table>
</div>
</Paper>
);
}
}
CustomPaginationActionsTable.propTypes = {
classes: PropTypes.object.isRequired,
};
export default withStyles(styles)(CustomPaginationActionsTable);
I think it might be related to this this post right here which talks about circular dependencies. Check your version compatibility.