useState in react hooks converting to functional component - javascript

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).

Related

Redux Toolkit Query not fetching data

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 :

How can I pass values or fields from one page to another page in ReactJS?

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).

Using axios to make use of a service not working

I'm trying to use S3 service to upload an image and it's telling me that certain variables aren't defined when I have defined them. I have imported axios and all the other stuff that are required
import React, { useState } from "react";
import ReactDOM from "react-dom";
import axios from "axios";
import Grid from "#material-ui/core/Grid";
import Button from "#material-ui/core/Button";
import Card from "#material-ui/core/Card";
import TextField from "#material-ui/core/TextField";
import CreateIcon from "#material-ui/icons/Create";
import Box from "#material-ui/core/Box";
import CardMedia from "#material-ui/core/CardMedia";
import MuiAlert from "#material-ui/lab/Alert";
import Snackbar from "#material-ui/core/Snackbar";
import { withStyles } from "#material-ui/core/styles";
import { makeStyles } from "#material-ui/core/styles";
import Chip from "#material-ui/core/Chip";
import Avatar from "#material-ui/core/Avatar";
import Slider from "#material-ui/core/Slider";
import Typography from "#material-ui/core/Typography";
import InputAdornment from "#material-ui/core/InputAdornment";
import { connect } from "react-redux";
function mapStateToProps(state) {
return {};
}
const useStyles = makeStyles((theme) => ({
root: {
"& > *": {
margin: theme.spacing(1),
marginLeft: theme.spacing(15),
},
},
input: {
display: "none",
},
}));
const useSliderStyles = makeStyles({
root: {
width: 250,
},
input: {
width: 100,
},
});
const UploadButton = () => {
const classes = useStyles();
return (
<div className={classes.root}>
<input
accept='image/*'
className={classes.input}
id='contained-button-file'
multiple
type='file'
/>
<label htmlFor='contained-button-file'>
<Button variant='contained' color='primary' component='span'>
Upload
</Button>
</label>
</div>
);
};
const StyledCard = withStyles({
root: { height: 600, width: 350 },
})(Card);
const PetitionForm = () => {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const [open, setOpen] = useState(false);
const [petition, validPetition] = useState(false);
const [noTitle, titleError] = useState(false);
const [noDescription, descriptionError] = useState(false);
const [hashtag, setHashtag] = useState("");
const [arrayOfHashtags, addHashtag] = useState([]);
const [money, setMoney] = React.useState(500);
const slider = useSliderStyles();
const handleTitleChange = (event) => setTitle(event.target.value);
const handleDescriptionChange = (event) => setDescription(event.target.value);
const handleClose = (event, reason) => {
if (reason === "clickaway") {
return;
}
};
const Alert = (props) => (
<MuiAlert elevation={6} variant='filled' {...props} />
);
const clearField = (event) => {
setOpen(true);
if (title.length > 0 && description.length > 0) {
validPetition(true);
setTitle("");
setDescription("");
addHashtag([]);
setHashtag("");
axios({
url: `call/s3/backend`,
method: "post",
data: {
images: imageArray.toByteArray(),
},
})
.then((res) => {
imageUrlArr = res.data;
axios({
url: `api/petition_posts`,
method: "post",
data: {
petition_post: {
title: title,
description: description,
hashtags: arrayOfHashtags.join(" "),
amount_donated: 0,
media: imageUrlArr,
goal: money,
card_type: "petition",
org_profile_id: 1,
},
},
})
.then((res) => {
console.log(res.data);
})
.catch((error) => console.log(error));
})
.catch((error) => console.log(error));
}
titleError(true ? title.length === 0 : false);
descriptionError(true ? description.length === 0 : false);
};
const handleDelete = (h) => () => {
addHashtag((arrayOfHashtags) =>
arrayOfHashtags.filter((hashtag) => hashtag !== h)
);
};
const handleHashtagChange = (event) => setHashtag(event.target.value);
const handleSliderChange = (event, newValue) => {
setMoney(newValue);
};
const handleInputChange = (event) => {
setMoney(event.target.value === "" ? "" : Number(event.target.value));
};
const newHashtag = () => {
if (arrayOfHashtags.length < 3) {
addHashtag((arrayOfHashtags) => arrayOfHashtags.concat(hashtag));
} else {
console.log("Too many hashtags");
}
};
const Hashtags = arrayOfHashtags.map((h) => (
<Chip
key={h.length}
size='small'
avatar={<Avatar>#</Avatar>}
label={h}
onDelete={handleDelete(h)}
/>
));
return (
<StyledCard>
<Box mt={1}>
<Grid container justify='center'>
<TextField
id='outlined-multiline-static'
multiline
rows={1}
variant='outlined'
placeholder='Title'
value={title}
onChange={handleTitleChange}
helperText={
open // only displays helper text if button has been clicked and fields haven't been filled
? !noTitle || petition
? ""
: "Can't be an empty field"
: ""
}
/>
</Grid>
</Box>
<Box mt={1}>
<Grid container justify='center'>
<CardMedia title='Petition'>
<UploadButton />
</CardMedia>
</Grid>
</Box>
<div className={slider.root}>
<Typography>Amount to raise</Typography>
<Box>
<Grid container justify='center'>
<Slider
min={500}
max={10000}
value={typeof money === "number" ? money : 0}
onChange={handleSliderChange}
aria-labelledby='input-slider'
/>
<TextField
className={slider.input}
value={money}
onChange={handleInputChange}
InputProps={{
startAdornment: (
<InputAdornment position='start'>$</InputAdornment>
),
}}
helperText={
money < 500 || money > 10000
? "Please enter a value between 500 and 10000"
: ""
}
/>
</Grid>
</Box>
</div>
<Box mt={1} mb={1}>
<Grid container justify='center'>
<TextField
size='small'
inputProps={{
style: { fontSize: 15 },
}}
id='outlined-multiline-static'
multiline
rows={1}
placeholder='Hashtags'
variant='outlined'
value={hashtag}
onChange={handleHashtagChange}
helperText={
arrayOfHashtags.length === 3
? "You reached the maximum amount of hashtags"
: ""
}
/>
<Button color='primary' onClick={newHashtag}>
Create!
</Button>
{arrayOfHashtags.length > 0 ? Hashtags : ""}
</Grid>
</Box>
<Box mt={1} justify='center'>
<Grid container justify='center'>
<TextField
size='small'
inputProps={{
style: { fontSize: 15 },
}}
id='outlined-multiline-static'
multiline
rows={5}
placeholder='Description'
variant='outlined'
value={description}
onChange={handleDescriptionChange}
helperText={
// only displays helper text if button has been clicked and fields haven't been filled
open
? !noDescription || petition
? ""
: "Can't be an empty field"
: ""
}
/>
</Grid>
</Box>
<Box mt={1}>
<Grid container justify='center'>
<Button onClick={clearField}>
<CreateIcon />
Create Petition!
</Button>
{open && petition && (
<Snackbar open={open} autoHideDuration={2000} onClose={handleClose}>
<Alert severity='success'>
You have successfully create a petition!
</Alert>
</Snackbar>
)}
{open && !petition && (
<Snackbar open={open} autoHideDuration={2000} onClose={handleClose}>
<Alert severity='error'>You're missing one or more fields</Alert>
</Snackbar>
)}
</Grid>
</Box>
</StyledCard>
);
};
export default connect(mapStateToProps)(PetitionForm);
This is the error I'm getting, someone mentioned something about the scope and I think that shouldn't matter when I'm trying to assign a value to a variable as far I as know
Line 109:19: 'imageArray' is not defined no-undef
Line 113:11: 'imageUrlArr' is not defined no-undef
Line 123:24: 'imageUrlArr' is not defined no-undef
Search for the keywords to learn more about each error.

React SyntheticEvent warning being thrown even with e.persistent()

I have a couple blocks of code that sets the state of by the user enter a value into and input and even checking a checkbox. They are both throwing the classic SyntheticEvent warning:
Warning: This synthetic event is reused for performance reasons. If you're seeing this, you're accessing the property buttons on a released/nullified synthetic event.
I have tried chacheing and e.persist() and its still throwing the warning on the onChange events:
const handleChange = (e) => {
e.persist();
const { name, checked } = e.target;
setHolidayData((prevState) => ({ ...prevState, [name]: checked }));
};
const updateValues = (e) => {
e.persist();
const { name, value } = e.target;
setHolidayData((prevState) => ({ ...prevState, [name]: value }));
};
These change events are on the inputs and check boxes respectively. What am i doing wrong here that the warnings are still being thrown?
Entire Component Code:
import React, { useState, useEffect, useCallback } from 'react';
import { makeStyles, withStyles } from "#material-ui/core/styles";
import _ from "lodash";
import Slide from "#material-ui/core/Slide";
import Button from '#material-ui/core/Button';
import Dialog from '#material-ui/core/Dialog';
import MuiDialogTitle from '#material-ui/core/DialogTitle';
import MuiDialogContent from '#material-ui/core/DialogContent';
import MuiDialogActions from '#material-ui/core/DialogActions';
import IconButton from '#material-ui/core/IconButton';
import CloseIcon from '#material-ui/icons/Close';
import Typography from '#material-ui/core/Typography';
import TextField from '#material-ui/core/TextField';
import FormControlLabel from '#material-ui/core/FormControlLabel';
import Checkbox from '#material-ui/core/Checkbox';
import DateFnsUtils from '#date-io/date-fns';
import {
MuiPickersUtilsProvider,
KeyboardDatePicker,
} from '#material-ui/pickers';
import moment from 'moment';
import { toast } from 'react-toastify';
import * as actions from "../../../Redux/Actions";
import { useDispatch, useSelector } from 'react-redux';
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="down" ref={ref} {...props} />;
});
const styles = (theme) => ({
root: {
margin: 0,
padding: theme.spacing(2),
},
closeButton: {
position: 'absolute',
right: theme.spacing(1),
top: theme.spacing(1),
color: theme.palette.grey[500],
},
});
const DialogTitle = withStyles(styles)((props) => {
const { children, classes, onClose, ...other } = props;
return (
<MuiDialogTitle disableTypography className={classes.root} {...other}>
<Typography variant="h6">{children}</Typography>
{onClose ? (
<IconButton aria-label="close" className={classes.closeButton} onClick={onClose}>
<CloseIcon />
</IconButton>
) : null}
</MuiDialogTitle>
);
});
const DialogContent = withStyles((theme) => ({
root: {
padding: theme.spacing(2),
},
}))(MuiDialogContent);
const DialogActions = withStyles((theme) => ({
root: {
margin: 0,
padding: theme.spacing(1),
},
}))(MuiDialogActions);
const HolidayDialog = (props) => {
const [noticeModal, setNoticeModal] = useState(props.open);
const [selectedDate, setSelectedDate] = useState(new Date());
const [holidayData, setHolidayData] = useState({});
const dispatch = useDispatch();
useEffect(() => {
setSelectedDate(moment(props.data.HolidayDate));
setNoticeModal(props.open);
setHolidayData(props.data);
}, [props.open]);
const user = useSelector(state => {
return JSON.stringify(state.main.user);
});
const handleDateChange = (date) => {
setSelectedDate(date);
};
const handleClose = () => {
props.onClose(false);
setNoticeModal(false);
};
const handleChange = (e) => {
e.persist();
const { name, checked } = e.target;
setHolidayData((prevState) => ({ ...prevState, [name]: checked }));
};
const updateValues = (e) => {
e.persist();
const { name, value } = e.target;
setHolidayData((prevState) => ({ ...prevState, [name]: value }));
};
const formSubmit = () => {
dispatch(actions.holiday_editHoliday(holidayData));
handleClose();
}
const handleSubmit = () => {
dispatch(actions.holiday_submitHoliday(holidayData));
handleClose();
}
const handleCreate = () => {
let createdHoliday = {
Active: true,
Branch: holidayData.Branch ? holidayData.Branch : '',
Close: holidayData.Close ? holidayData.Close : '',
CoOp: holidayData.CoOp ? holidayData.CoOp : false,
HolidayDate: selectedDate ? moment(selectedDate).format('MM/DD/YYYY') : moment().format('MM/DD/YYYY'),
HolidayName: holidayData.HolidayName ? holidayData.HolidayName : "",
Open: holidayData.Branch ? holidayData.Branch : '',
Phone: holidayData.Phone ? holidayData.Phone : true,
Web: holidayData.Web ? holidayData.Web : true,
Hours: holidayData.Hours ? holidayData.Hours : '',
}
dispatch(actions.holiday_createHoliday(createdHoliday));
handleClose();
}
const handlePublish = () => {
const userObj = JSON.parse(user);
const userName = `CCU\\${userObj.UserName}`;
if (userName != holidayData.SubmittedBy) {
dispatch(actions.holiday_publishHoliday(holidayData));
handleClose();
} else {
toast.error("Submitter & Publisher cannot be the same person", {
position: "top-right",
autoClose: 5000,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: false,
draggable: true,
progress: undefined,
});
handleClose();
}
}
const handleDecline = () => {
dispatch(actions.holiday_declineHoliday(holidayData));
handleClose();
}
return (
<Dialog
open={noticeModal}
TransitionComponent={Transition}
keepMounted
onClose={handleClose}
aria-labelledby="notice-modal-slide-title"
aria-describedby="notice-modal-slide-description"
>
<DialogTitle id="customized-dialog-title" onClose={handleClose}>
{holidayData.HolidayName ? holidayData.HolidayName : 'Create New Holiday'}
</DialogTitle>
<form noValidate autoComplete="off" id="HolidayForm" onSubmit={(e) => { e.preventDefault(); formSubmit(); } }>
<DialogContent dividers>
<div className="row">
<div className="col">
<TextField required name="HolidayName" id="outlined-basic" label="Holiday Name" variant="outlined" onChange={updateValues} value={holidayData.HolidayName || ''} disabled={holidayData.Submitted != null}/>
</div>
<div className="col">
<TextField id="outlined-basic" name="Branch" label="Branch" variant="outlined" onChange={updateValues} value={holidayData.Branch || ''} disabled={holidayData.Submitted != null}/>
</div>
</div>
<div className="row mt-3">
<div className="col">
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<KeyboardDatePicker
disableToolbar
variant="inline"
format="MM/dd/yyyy"
margin="normal"
id="date-picker-inline"
label="Holiday Date *"
value={selectedDate}
onChange={handleDateChange}
KeyboardButtonProps={{
'aria-label': 'change date',
}}
disabled={holidayData.Submitted != null}
/>
</MuiPickersUtilsProvider>
</div>
<div className="col">
<TextField id="outlined-basic" name="Hours" label="Hours" variant="outlined" onChange={updateValues} value={holidayData.Hours || ''} disabled={holidayData.Submitted != null}/>
</div>
</div>
{holidayData.Hours ? (
<div className="row mt-3">
<div className="col">
<TextField id="outlined-basic" name="Open" label="Open" variant="outlined" onChange={updateValues} value={holidayData.Open || ''} disabled={holidayData.Submitted != null}/>
</div>
<div className="col">
<TextField id="outlined-basic" name="Close" label="Close" variant="outlined" onChange={updateValues} value={holidayData.Close || ''} disabled={holidayData.Submitted != null}/>
</div>
</div>
) : (
<div></div>
)}
<div className="row mt-3">
<div className="col d-flex flex-column">
<FormControlLabel
control={
<Checkbox
checked={holidayData.Web || false}
value={holidayData.Web}
onChange={handleChange}
name="Web"
color="primary"
disabled={holidayData.Submitted != null}
/>
}
label="Show on Web?"
/>
<FormControlLabel
control={
<Checkbox
checked={holidayData.CoOp || false}
value={holidayData.CoOp}
onChange={handleChange}
name="CoOp"
color="primary"
disabled={holidayData.Submitted != null}
/>
}
label="CoOp Holiday?"
/>
</div>
<div className="col d-flex flex-column">
<FormControlLabel
control={
<Checkbox
checked={holidayData.Phone || false}
value={holidayData.Phone}
onChange={handleChange}
name="Phone"
color="primary"
disabled={holidayData.Submitted != null}
/>
}
label="Use in IVR?"
/>
<FormControlLabel
control={
<Checkbox
checked={holidayData.Active || true}
value={holidayData.Active}
onChange={handleChange}
disabled
name="Active"
color="primary"
/>
}
label="Active"
/>
</div>
</div>
</DialogContent>
<DialogActions className="d-flex">
{holidayData.Submitted ? (
<div className="mr-auto">
<Button variant="outlined" color="primary" onClick={handlePublish}>
Publish
</Button>
<Button variant="outlined" color="secondary" className="ml-2" onClick={handleDecline}>
Decline
</Button>
</div>
) : (
<div className="mr-auto">
<Button variant="outlined" color="primary" onClick={handleSubmit}>
Submit
</Button>
</div>
)}
<Button variant="outlined" onClick={handleClose} color="default">
Cancel
</Button>
{holidayData.Active ? (
<Button variant="outlined" color="primary" type="submit" form="HolidayForm" disabled={holidayData.Submitted != null}>
Update Holiday
</Button>
) : (
<Button variant="outlined" color="primary" onClick={handleCreate} form="HolidayForm">
Create Holiday
</Button>
)}
</DialogActions>
</form>
</Dialog>
)
}
export default HolidayDialog;

nested Delete Function Causes undefined Error

i've 2 components 1/ parent ----> which pass a delete function to child Component but it causes undefined
TypeError: Cannot read property 'onHandleDelete' of undefined
i tried every thing that react docs provides and there is nothing works for me
the parent Compnent
import React from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
// import isEmpty from 'lodash/isEmpty';
import { connect } from 'react-redux';
import isObject from 'lodash/isObject';
import classnames from 'classnames';
import moment from 'moment-hijri';
import uuid from 'uuid';
// Material-UI
import { withStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import Paper from '#material-ui/core/Paper';
import Typography from '#material-ui/core/Typography';
// components
import Actions from './Actions';
import Supervisor from './Supervisor';
// Forms
import Entity from '~/Components/Entity';
import { BaseFormComponent, Form, FormBreak, FormDivider, FormContainer, FormItem } from '~/Components/FormComponent';
import { LabelAndValue } from '~/Components/FormComponent/Controls';
import {
isRequired,
noEnglish,
isObjectRequired,
} from '~/Services/Validators';
// Redux
import OfficesActions from '~/Redux/Actions/Offices';
import { VisitStatus } from '~/Services/StaticLookups';
import Strings from '~/Services/Strings';
import Notifications from '~/Services/Notifications';
import Message from '~/Components/Message';
import Navigate from '~/Services/Navigate';
import styles from './styles';
#withStyles(styles)
class AssignmentsEditorScreen extends BaseFormComponent {
constructor(props) {
super(props);
this.initState({
supervisors: [],
insititution: [],
inistitutionsLookup: [],
selectedSupervisors: [],
previousSupervisorsFromId: [],
plannedVisitInfoFromId: {},
institutionDetails: {},
account: {},
error: false,
form: {
id: {
type: this.types.string,
value: 0,
},
institutionId: {
type: this.types.number,
validators: [ isRequired() ],
},
visitTypeId: {
type: this.types.number,
validators: [ isRequired() ],
},
startDate: {
type: this.types.object,
validators: [ isObjectRequired() ]
},
endDate: {
type: this.types.object,
validators: [ isObjectRequired() ]
},
office: {
type: this.types.string,
UIOnly: true
},
plannedVisitSupervisors: {
type: this.types.string,
UIOnly: true
},
visitStatus: {
type: this.types.string,
UIOnly: true
},
reason: {
type: this.types.string,
validators: [ noEnglish() ],
},
},
});
}
componentDidMount() {
super.componentDidMount();
const id = get(this, 'props.match.params.id', null);
const { offices, account } = this.props;
this.searchableEntity.get();
if (id) {
this.addFormFields({
referenceNumber: {
type: this.types.string,
UIOnly: true
},
});
this.entity.get({ id });
} else {
this.removeFormFields([ 'referenceNumber' ]);
}
if (!offices.isSet) {
this.props.getOffices();
}
this.setState({ account });
}
componentDidUpdate(prevProps) {
if(this.state.account !== this.props.account) {
const employeeOfficeId = this.props.account.myRoles.find(item => item.roleName === 'PTSupervisionEmployees').officeId;
// // To Switch to employee Office Once he Opens The Editor
this.handleOfficesChange(employeeOfficeId);
this.setFieldValue('office', employeeOfficeId);
this.setState({ account: this.props.account });
}
}
onSubmit() {
const id = get(this, 'props.match.params.id', null);
const { selectedSupervisors, previousSupervisorsFromId } = this.state;
let plannedVisitors = [];
if(selectedSupervisors.length > 0) {
selectedSupervisors.map(item => {
plannedVisitors.push({ supervisorName: item.name });
});
} else {
plannedVisitors = [];
}
// To Append The Previous Supervisors with the newest supervisors
if(previousSupervisorsFromId.length > 0) {
previousSupervisorsFromId.map(item => {
plannedVisitors.push({ supervisorName: item.supervisorName });
});
}
if (this.isFormValid) {
this.entity.post({
...this.formValues,
plannedVisitSupervisors: [ ...plannedVisitors ],
// to set id = 0 --> in create Mode || id Value in update Mode
id: id ? id : 0
});
} else {
console.log('this', this.formValues,);
this.showFormErrors();
}
}
onEntityPosted() {
const id = get(this, 'props.match.params.id', null);
if(id) {
Notifications.notify('success', Strings.assignmentUpdatedSuccessfuly);
} else {
Notifications.notify('success', Strings.assignmentSavedSuccessfully);
}
Navigate.go('/plannedvisits');
}
onEntityPostedError(data) {
if(data === 'Failed to create visit!, another visit is on for the institution!') {
Notifications.notify('error', Strings.duplicatPlannedVisits);
this.setState({ error: true });
}
}
onEntityReceived(data) {
const previousSupervisorsFromId = [ ...data.plannedVisitSupervisors ];
const plannedVisitInfoFromId = { ...data };
if(isObject(data)) {
this.updateFormValues(data, () => {
if(data.hasOwnProperty('visitReasonId')) {
this.addFormFields({
visitReasonId: {
type: this.types.number,
validators: [ isRequired() ],
value: data.visitReasonId,
}
});
}
});
}
this.setState({
previousSupervisorsFromId,
plannedVisitInfoFromId
});
}
onSearchableEntityReceived(data) {
if(data && data.licensingInstitutionsModel) {
const insititution = [ ...data.licensingInstitutionsModel ];
if (data.licensingInstitutionsModel && data.licensingInstitutionsModel.length > 0) {
{
data.licensingInstitutionsModel.map(item => {
this.setState(prevState => ({
inistitutionsLookup: prevState.inistitutionsLookup.concat({
id: item.institutionId,
nameAr: item.fullName
}),
insititution
}));
});
}
}
}
}
onSupervisorsByOfficeEntityReceived(data) {
this.setState({ supervisors: data.result });
}
handleOfficesChange(officeId) {
this.supervisorsByOfficeEntity.get({ officeId });
}
onHandleDelete(member) {
console.log('member', member);
}
x(m) {
console.log('member');
}
handleReasonField(id) {
if(id === 1) {
this.addFormFields({
visitReasonId: {
type: this.types.string,
validators: [ isRequired() ]
},
});
} else {
this.removeFormFields([ 'visitReasonId' ]);
}
}
getInstitutionValues(institutionId) {
const { insititution } = this.state;
if(insititution && insititution.length > 0) {
const institutionDetails = insititution.filter(item => item.institutionId === institutionId);
this.setState({ institutionDetails });
}
}
handleAddMember(value) {
const member = this.state.supervisors.find(item => item.name === value);
if(member) {
// in order not to allow add multiple supervisors withe the same name
const isInPreviousSupervisors = this.state.previousSupervisorsFromId.find(item => item.supervisorName === member.name);
if(!isInPreviousSupervisors) {
const selectedSupervisors = [ ...this.state.selectedSupervisors ];
selectedSupervisors.push(member);
this.setState({ selectedSupervisors });
} else {
Notifications.notify('error', `${member.displayName} ${Strings.userAlreadyInTheList} ${member.name}`);
}
}
}
get offices() {
const { offices } = this.props;
if(offices.list.length >= 1) {
const lookup = {};
offices.list.forEach(item => {
lookup[item.id] = item.name;
});
return lookup;
}
return {};
}
get plannedVisitsSupervisors() {
const lookup = {};
this.state.supervisors.forEach(item => {
const isSelectedBefore = this.state.selectedSupervisors.find(sItem => sItem.name === item.name);
if(!isSelectedBefore) {
lookup[item.name] = item.displayName;
}
});
return lookup;
}
get getSupervisors() {
const { selectedSupervisors, previousSupervisorsFromId } = this.state;
return selectedSupervisors.concat(previousSupervisorsFromId);
}
render() {
// const { form, inistitutions, supervisorsByOffice, previousSupervisorsFromId } = this.state;
const { form, error, inistitutionsLookup, plannedVisitInfoFromId } = this.state;
const { classes } = this.props;
const id = get(this, 'props.match.params.id', null);
const inistitutionsCheck = inistitutionsLookup && inistitutionsLookup.length === 0;
// const supervisorsCheck = supervisorsByOffice && supervisorsByOffice.length === 0;
const disabled = plannedVisitInfoFromId && plannedVisitInfoFromId.plannedVisitActions && !plannedVisitInfoFromId.plannedVisitActions.allowEdit;
const {
TextField,
LookupSelectField,
StaticLookupSelectField,
SelectAutocompleteField,
Date2Field,
} = this;
return (
<React.Fragment>
<Entity
storeId={'Supervision-PlannedVisit-Editor'}
entityRef={ref => { this.entity = ref; }}
onEntityReceived={data => this.onEntityReceived(data)}
onEntityPosted={data => this.onEntityPosted(data)}
onEntityPostedError={data => this.onEntityPostedError(data)}
render={store => (
<Form loading={store.loading}>
<Grid container spacing={24}>
<If condition={error}>
<Grid item xs={12}>
<Message variant={'error'} text={Strings.duplicatPlannedVisits} />
</Grid>
</If>
<Grid item xs={9}>
<Paper elevation={1} className={classes.box1}>
<fieldset className={classes.fieldSet}>
<legend>{Strings.assignmentDetails}</legend>
<FormContainer>
<FormItem lg={6}>
<div className={classnames(classes.placeholder, id || inistitutionsCheck ? classes.disabledField : {})}>
<SelectAutocompleteField
name={'institutionId'}
label={Strings.assignmentInstitutionName}
emptyString={Strings.searchByNameAndLicense}
disabled={id || inistitutionsCheck}
data={inistitutionsLookup}
onChange={field => this.getInstitutionValues(field.value)}
// onSearch={e => console.log('e', e)}
/>
</div>
</FormItem>
<FormItem lg={form.visitTypeId.value === 1 ? 3 : 6}>
<LookupSelectField
name={'visitTypeId'}
label={Strings.assignmentvisitType}
lookup={'VisitType'}
onChange={field => this.handleReasonField(field.value)}
disabled={disabled}
/>
</FormItem>
<If condition={form.visitTypeId.value === 1 && form.visitReasonId}>
<FormItem lg={3}>
<LookupSelectField
name={'visitReasonId'}
label={Strings.assignmentvisitReason}
lookup={'VisitReason'}
disabled={disabled}
/>
</FormItem>
</If>
<FormItem lg={6}>
<Choose>
<When condition={disabled}>
<LabelAndValue
label={Strings.assignmentvisitStartDate}
value={plannedVisitInfoFromId.startDate.hijriDate}
/>
</When>
<Otherwise>
<Date2Field
name={'startDate'}
label={Strings.assignmentvisitStartDate}
minDate={[
moment().iYear(),
moment().iMonth() + 1,
moment().iDate()
]}
/>
</Otherwise>
</Choose>
</FormItem>
<FormItem lg={6}>
<Choose>
<When condition={disabled}>
<LabelAndValue
label={Strings.assignmentvisitEndDate}
value={plannedVisitInfoFromId.endDate.hijriDate}
/>
</When>
<Otherwise>
<Date2Field
name={'endDate'}
label={Strings.assignmentvisitEndDate}
minDate={[
moment().iYear(),
moment().iMonth() + 1,
moment().iDate()
]}
/>
</Otherwise>
</Choose>
</FormItem>
</FormContainer>
</fieldset>
</Paper>
<Paper elevation={1} className={classes.box}>
<fieldset className={classes.fieldSet}>
<legend>
<Choose>
<When condition={disabled}>
{Strings.assignedSupervisors}
</When>
<Otherwise>
{Strings.addSupervisors}
</Otherwise>
</Choose>
</legend>
<FormContainer className={classes.supervisorsContainer}>
<If condition={!disabled}>
<FormItem>
<div className={ classes.lookup }>
<StaticLookupSelectField
name= {'office'}
label={Strings.office}
lookup= {this.offices}
onChange={field => this.handleOfficesChange(field.value)}
/>
</div>
</FormItem>
<FormItem>
<StaticLookupSelectField
name={'plannedVisitSupervisors'}
label={Strings.supervisorListName}
lookup={this.plannedVisitsSupervisors}
onChange={field => this.handleAddMember(field.value)}
/>
</FormItem>
</If>
<If condition={this.getSupervisors.length > 0}>
<If condition={!disabled}>
<FormBreak />
<FormDivider />
<Typography variant='subtitle1' className={classes.supervisorsHeader}>
{Strings.assignedSupervisors}
</Typography>
</If>
<FormContainer className={classes.supervisorsContainer}>
<For each='member' of={this.getSupervisors} index='i'>
<FormItem lg={4} key={`${i}_${uuid()}`}>
<Supervisor
data={member}
onHandleDelete={data => this.onHandleDelete(data)}
disabled={disabled}
/>
</FormItem>
</For>
</FormContainer>
</If>
</FormContainer>
</fieldset>
</Paper>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth>
<TextField
multiline
name={'reason'}
label={Strings.assignmentvisitreason}
disabled={disabled}
/>
</FormItem>
</Paper>
</Grid>
<Grid item xs={3}>
{/* =========== Sidebar ============= */}
<If condition={form && form.visitStatus}>
<Paper elevation={1} className={classes.box}>
{/* lookup is Needed */}
<FormItem fullWidth>
<StaticLookupSelectField
name={'visitStatus'}
label={Strings.assignmentvisitStatus}
lookup={VisitStatus}
disabled
/>
</FormItem>
</Paper>
</If>
<If condition={form && form.referenceNumber}>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth>
<TextField
name={'referenceNumber'}
label={Strings.violationReferenceNumber}
disabled
/>
</FormItem>
</Paper>
</If>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth style={{ marginBottom: 10 }}>
<Actions disabled={disabled} onSubmit={() => this.onSubmit()} />
</FormItem>
</Paper>
</Grid>
</Grid>
</Form>
)}
/>
{/* To get all institutions */}
<Entity
storeId={'Supervision-Assignment-Searchable-Institution'}
entityRef={ref => { this.searchableEntity = ref;}}
onEntityReceived={data => this.onSearchableEntityReceived(data)}
/>
{/* To get supervisors by office */}
<Entity
storeId={'Supervision-Assignment-Supervisors-By-Office'}
entityRef={ref => { this.supervisorsByOfficeEntity = ref;}}
onEntityReceived={data => this.onSupervisorsByOfficeEntityReceived(data)}
/>
</React.Fragment>
);
}
}
AssignmentsEditorScreen.propTypes = {
classes: PropTypes.object,
offices: PropTypes.object,
account: PropTypes.object,
getOffices: PropTypes.func
};
const mapStateToProps = store => ({
offices: store.offices,
account: store.account.data || {}
});
const mapDispatchToProps = dispatch => ({
getOffices: () => dispatch(OfficesActions.get()),
});
AssignmentsEditorScreen.propTypes = {
classes: PropTypes.object,
};
export default connect(
mapStateToProps,
mapDispatchToProps
)(AssignmentsEditorScreen);
the child Component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '#material-ui/core/styles';
import Typography from '#material-ui/core/Typography';
import Paper from '#material-ui/core/Paper';
import Icon from '#material-ui/core/Icon';
import IconButton from '#material-ui/core/IconButton';
import DeleteIcon from '#material-ui/icons/Delete';
import Tooltip from '#material-ui/core/Tooltip';
import strings from '~/Services/Strings';
import { supervisor } from './styles';
#withStyles(supervisor)
class Supervisor extends Component {
render() {
const { classes, data, disabled } = this.props;
console.log('da', data);
return (
<Paper className={classes.memberItem}>
<If condition={!disabled}>
<Tooltip title={strings.delete}>
<IconButton className={classes.delete} onClick={() => this.props.onHandleDelete(data)}>
<DeleteIcon />
</IconButton>
</Tooltip>
</If>
<div className={classes.memberIconWrapper}>
<Icon className={classes.memberIcon}>person</Icon>
</div>
<div className={classes.memberDetails}>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.supervisorNameSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={data.displayName}>
{data.displayName}
</When>
<Otherwise>
<Choose>
<When condition={data.name}>
{data.name}
</When>
<Otherwise>
<Choose>
<When condition={data.supervisorName}>
{data.supervisorName}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Otherwise>
</Choose>
</Otherwise>
</Choose>
</Typography>
</div>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.assignedVisitCountSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={typeof(data.assignedVisitCount) === 'number'}>
{data.assignedVisitCount}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Typography>
</div>
<div className={classes.subInfo}>
<Typography gutterBottom className={classes.memberJobTitle} variant='subtitle1'>
{strings.requiredVisitsCountPerMonthSub}
</Typography>
<Typography className={classes.memberName} variant='subtitle2'>
<Choose>
<When condition={typeof(data.requiredVisitsCountPerMonth) === 'number'}>
{data.requiredVisitsCountPerMonth}
</When>
<Otherwise>
{strings.emptyString}
</Otherwise>
</Choose>
</Typography>
</div>
</div>
</Paper>
);
}
}
Supervisor.propTypes = {
classes: PropTypes.object,
data: PropTypes.object,
disabled: PropTypes.bool,
key: PropTypes.string,
onHandleDelete: PropTypes.func,
};
export default Supervisor;
here is my parent Component
<For each='member' of={this.getSupervisors} index='i'>
<FormItem lg={4} key={`${i}_${uuid()}`}>
<Supervisor
data={member}
onHandleDelete={data => this.onHandleDelete(data)}
disabled={disabled}
/>
</FormItem>
</For>
here is onHandleDelete Function
onHandleDelete(data) {
console.log('member');
}
here is my Child Component(Supervisor)
<If condition={!disabled}>
<Tooltip title={strings.delete}>
<IconButton className={classes.delete} onClick={() => this.props.onHandleDelete(data)}>
<DeleteIcon />
</IconButton>
</Tooltip>
</If>
this is the error from console
Uncaught TypeError: Cannot read property 'onHandleDeletion' of undefined
at Object.onHandleDeletion (index.js:497)
at onClick (Supervisor.js:24)
at HTMLUnknownElement.callCallback (react-dom.development.js:100)
at Object.invokeGuardedCallbackDev (react-dom.development.js:138)
at Object.invokeGuardedCallback (react-dom.development.js:187)
at Object.invokeGuardedCallbackAndCatchFirstError (react-dom.development.js:201)
at executeDispatch (react-dom.development.js:461)
at executeDispatchesInOrder (react-dom.development.js:483)
at executeDispatchesAndRelease (react-dom.development.js:581)
at executeDispatchesAndReleaseTopLevel (react-dom.development.js:592)
at forEachAccumulated (react-dom.development.js:562)
at runEventsInBatch (react-dom.development.js:723)
at runExtractedEventsInBatch (react-dom.development.js:732)
at handleTopLevel (react-dom.development.js:4476)
at batchedUpdates$1 (react-dom.development.js:16659)
at batchedUpdates (react-dom.development.js:2131)
at dispatchEvent (react-dom.development.js:4555)
at interactiveUpdates$1 (react-dom.development.js:16714)
at interactiveUpdates (react-dom.development.js:2150)
at dispatchInteractiveEvent (react-dom.development.js:4532)
where data is an object that for sure it carries data
i expect logging data in the console

Categories