The code below I have provided , one example opens the dialog. And the dialog has add functionality which is the addEmail where in you can add multiple fields which is inside the dialog.
I wanna know is that when I close the dialog using the onClick={handleClose} it should reset the dialog, fields that I added should not show after I close since I did not save it.
So when I click cancel it should reset the state.
Thanks for any idea.
for example here I added fields when I close this and open again these field should not show cause it should reset when I close.
#interface.ts
export type EditPropertiesProps = {
open: boolean;
handleClose: () => void;
selectedRow: IRegional
};
#Code snippet - main page --- this calls and opens the dialog
const handleClose = () => {
console.log('here')
setOpen(false);
};
<EditProperties open={open} handleClose={handleClose} selectedRow={selectedRow} />
#EditProperties ts code
export const RegionalListData: IRegionalList[] = [
{
id: 4,
name: "Associate Director of Construction Ops",
column: "associateDirectorofConstructionOps",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
{
id: 5,
name: "CAM Manager",
column: "camManager",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
{
id: 6,
name: "CAO-Chief Administrative Officer",
column: "caoChiefAdministrativeOfficer",
emails: [
{
emailAddress: "associateDir#gmail.com",
firstName: "Associate",
lastName: "Director",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
},
];
type InitialReqPaylod = {
accountId: number;
regionalRoleUserDto: IRegional;
};
type IData = {
regionName: string;
marketName: string;
subRegionName: string;
};
type IEmail = {
emailAddress: string;
firstName: string;
id: number;
lastName: string;
};
const EditProperties: FC<EditPropertiesProps> = ({
open,
handleClose,
selectedRow,
}) => {
const dispatch = useAppDispatch();
const [isEmailOpen, setOpenEmail] = useState(false);
const [fetching, setFetching] = useState(false);
const [RegionalList, setRegionalList] = useState<IRegionalList[]>(
RegionalListData
);
const [data, setData] = useState<IData>({
regionName: "",
marketName: "",
subRegionName: "",
});
const [regionalId, setRegionalId] = useState<number | null>(null);
const [emailCurrentIndex, setEmailCurrentIndex] = useState<number | null>(
null
);
const [selectedEmailId, setSelectedEmailId] = useState<number | null>(null);
const { isSuccess } = useAppSelector((state) => state.yardUser);
const { isSaveSuccess } = useAppSelector((state) => state.region);
const email = useAppSelector((state) => state.yardUser);
const [emailOptions, setEmailOptions] = useState<IEmail[]>([]);
const emailList = email.data ? email.data.data : [];
useEffect(() => {
if (selectedRow) {
setData({
regionName: selectedRow["regionName"],
marketName: selectedRow["marketName"],
subRegionName: selectedRow["subRegionName"],
});
let regional = [...RegionalList];
for (const k in selectedRow) {
regional.map((prop: IRegionalList) => {
if (prop.column === k) {
prop.emails = selectedRow[k] ? selectedRow[k] : [];
}
});
}
setRegionalList(regional);
}
}, [selectedRow]);
const [maxWidth, setMaxWidth] = React.useState<DialogProps["maxWidth"]>("md");
const fetchEmailResult = React.useMemo(
() =>
throttle(
(event: any, callback: (results: IEmail[]) => void) => {
const payload: IYardUserRequestPayload | InitialReqPaylod = {
accountId: 1,
searchString: event.target.value,
};
fetch(
`https://jsonplaceholder.typicode.com/users?email=${event.target.value}`
)
.then((res) => res.json())
.then((res) => res.data ? callback(res.data.slice(0, 10)) : callback([]))
},
200
),
[]
);
const emailOnChange = (event: any, regionalId: number, index: number, emailId: number) => {
setRegionalId(regionalId);
setEmailCurrentIndex(index);
setSelectedEmailId(emailId);
fetchEmailResult(event,(results: IEmail[]) => {
console.log('results' , results)
if (results.length) setEmailOptions(results);
});
};
useEffect(() => {
if (isSaveSuccess) {
handleClose();
}
}, [isSaveSuccess]);
useEffect(() => {
if (isSuccess) {
setFetching(false);
}
}, [isSuccess]);
const addEmail = (id: number) => {
setRegionalList((list) =>
list.map((item) => {
if (item.id === id) {
return {
...item,
emails: [
...item.emails,
{
emailAddress: "",
firstName: "",
lastName: "",
id: Math.floor(Math.random() * 999),
fetching: false,
},
],
};
}
return item;
})
);
};
const deleteEmail = (email: IEmail, regionId: number) => {
const regionalListCopy = [...RegionalList].map((prop: IRegionalList) => {
if (prop.id === regionId) {
return {
...prop,
emails: prop.emails.filter((prop) => prop.id !== email.id),
};
}
return { ...prop };
});
setRegionalList(regionalListCopy);
};
const setOnChangeOption = (email) => {
setSelectedEmailId(null);
setRegionalList((list) =>
list.map((item) => {
if (item.id === regionalId) {
return {
...item,
emails: [
...item.emails.map((prop) => {
return {
...prop,
...email,
};
}),
],
};
}
return item;
})
);
};
const EmailItem = ({ email, mIndex, prop }) => (
<>
<div style={{ display: "block" }} key={email.id}>
<div
style={{
display: "flex",
justifyContent: "space-between",
alignItems: "center",
marginTop: 15
}}
>
<Autocomplete
options={emailOptions}
getOptionLabel={(option: IEmail) => option.emailAddress}
onInputChange={($event) => emailOnChange($event, prop.id, mIndex, email.id)}
onChange={($event, value) => setOnChangeOption(value)}
fullWidth
open={email.id === selectedEmailId}
renderInput={(params) => (
<TextField size="small" {...params} variant="standard" />
)}
renderOption={(props, option) => {
return (
<Box component="li" {...props}>
{option.emailAddress}
</Box>
);
}}
/>
<DeleteIcon
style={{ color: "red", cursor: "pointer" }}
onClick={() => deleteEmail(email, prop.id)}
/>
</div>
<div
style={{
fontSize: ".8em",
display: "flex",
justifyContent: "space-between",
}}
>
<span style={{ paddingTop: 5 }}>
Email : {email.emailAddress}
Full Name: {email.firstName} {email.lastName}
</span>
{/* <span style={{ paddingRight : 40 }}>{fetching ? "Fetching...." : null}</span> */}
</div>
</div>
</>
);
return (
<Dialog
maxWidth={maxWidth}
open={open}
onClose={handleClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">Edit</DialogTitle>
<DialogContent>
<Card sx={{ minWidth: 275 }} style={{ padding: 20 }}>
<div>
<span>Sub-Region (Sub-Division)</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Region (Division)"
variant="filled"
value={data.regionName}
/>
</FormControl>
</div>
<div style={{ marginTop: 10 }}>
<span>Sub-Region (Sub-Division)</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Sub-Region (Sub-Division)"
variant="filled"
value={data.subRegionName}
/>
</FormControl>
</div>
<div style={{ marginTop: 10 }}>
<span>Market</span>
<Divider style={{ marginTop: 10 }} />
<FormControl sx={{ mt: 2, minWidth: 720 }}>
<TextField
label="Market"
variant="filled"
value={data.marketName}
/>
</FormControl>
</div>
</Card>
{RegionalList.map((prop: IRegionalList, index: number) => (
<Card
sx={{ minWidth: 275 }}
style={{ overflow: "visible", padding: 20, marginTop: 20 }}
key={prop.id}
>
<div style={{ display: "flex", alignItems: "center" }}>
{prop.name}*{" "}
<AddIcon
style={{ marginLeft: 5, cursor: "pointer" }}
onClick={() => addEmail(prop.id)}
/>
</div>
<Divider style={{ marginTop: 10 }} />
{prop.emails.map((email: IEmail, mIndex: number) => (
<EmailItem
key={email.id}
prop={prop}
email={email}
mIndex={mIndex}
/>
))}
</Card>
))}
</DialogContent>
<DialogActions
style={{ marginTop: "20px", marginRight: "20px", marginBottom: "20px" }}
>
<Button onClick={handleClose}>Cancel</Button>
<Button variant="contained" onClick={() => saveChanges()} autoFocus>
Save Changes
</Button>
</DialogActions>
</Dialog>
);
};
export default EditProperties;
You need just reset all used states as values of form when clicking handleClose, my suggestion would be to use just one object state for form values.
Example:
const onClose = () => {
handleClose();
setRegionalList(RegionalListData);
}
return (
<Dialog
maxWidth={maxWidth}
open={open}
onClose={onClose}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
Related
I'm struggling with Formik when using custom component for <Field> and my own onChange for this input.
The problem is that whenever I resetForm() (it's now set inside AutoSubmitHandler just for tests), the values are set well, it means that I get { q: ''} after each reset, but the value inside input itself stays filled.
Reproduction steps:
I type something in the input - "foo"
I get console.logged the values: { q: "foo" }
The resetForm() triggers and I get { q: ''}
But in the input I can still see "foo"
It looks like this:
const CustomDarkTextField = styled(TextField)<TextFieldProps>(() => ({
width: '50%',
marginBottom: '10px',
bgcolor: '#5C677D',
'& .MuiInputBase-root': {
bgcolor: '#5C677D',
},
'& .MuiInputBase-input': {
color: 'white',
},
'& .MuiFormLabel-root': {
color: 'white',
fontWeight: 600,
},
'& .MuiFormLabel-root.Mui-focused': {
color: 'white',
fontWeight: 600,
},
'& .MuiFormHelperText-root.Mui-error': {
color: '#F77F00',
},
'& .MuiOutlinedInput-root.Mui-focused': {
'& > fieldset': { border: '0' },
},
'& .MuiOutlinedInput-root.Mui-error': {
'& > fieldset': { borderColor: '#F77F00' },
},
'& .MuiTypography-root': {
color: 'white',
fontWeight: 600,
},
}));
export const FilterCustomDarkTextField = ({ field, label, onChange, setFieldValue }: FilterTextFieldProps) => {
return (<CustomDarkTextField name={field?.name} label={label} onChange={e => onChange(e, setFieldValue)} />);
};
and my filter form component:
return (
<div>
<Formik
initialValues={defaultFilterValues}
onSubmit={(values) => {
handleSubmit(values);
}}
enableReinitialize={true}
>
{({ setFieldValue, values }) => (
<Form className='form flex flex-col gap-4 mx-auto my-8 w-full items-center'>
<h2 className="self-start">Data</h2>
{Object.keys(filterFields).map(field => (
<>
<Field
key={field}
{...filterFields[field as keyof typeof filterFields]}
setFieldValue={setFieldValue}
/>
</>
))}
<AutoSubmitHandler />
</Form>
)}
</Formik>
</div>
);
AutoSubmit:
const AutoSubmitHandler = () => {
const { values, resetForm } = useFormikContext();
useEffect(() => {
console.log(values);
resetForm();
}, [values]);
return null;
};
fields:
const FILTER_FIELDS = {
football: {
q: {
name: 'q',
label: 'name/surname',
component: FilterCustomDarkTextField,
onChange: debouncedHandleChange,
},
},
};
onChange method:
export const debouncedHandleChange = _.debounce((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>, setFieldValue) => {
const { name, value } = e.target;
setFieldValue(name, value);
}, 1500);
I'm trying to fetch data using api and show the data in my datagrid. but initially the data is not loading. though I can get the data, and I don't know why it doesn't show in the datagrid. What I'm actually doing is, I have a common function for datagrid along with search option in one file. I'm getting the getting the data in another file. Now everytime I make a change and save the file, it shows the data, but when I refresh the page the data is not showing again. kindly help me figure out. Thanks in advance
this the code where I'm getting the data
const columns = [
{ field: 'role', headerName: 'Role', },
{ field: 'counterParty', headerName: 'Counter Party', },
{ field: 'tokens', headerName: 'Token', },
{ field: 'date', headerName: 'Date', },
{ field: 'comment', headerName: 'Comments', }
];
export default function TransactionCard(props) {
const [TransactionData, setTransactionData] = useState([]);
const [loading, setLoading] = useState(true);
// setLoading(loading, true);
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
catch (error) {
console.log(error)
}
})
}, [])
console.log(TransactionData)
return (
<>
<Card {...props}>
<CardContent>
<DataGridHelper title='Transaction' rows={TransactionData} columns={columns} />
</CardContent>
</Card>
</>
);
}
This is Where I'm getting the data
const DataGridHelper = ({ rows, columns, title }) => {
const [platform, setPlatform] = useState([]);
const [searchText, setSearchText] = useState('');
const [Rows, setRows] = useState([]);
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, []);
console.log(Rows);
function escapeRegExp(value) {
return value.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&');
}
const requestSearch = (searchValue) => {
const searchRegex = new RegExp(escapeRegExp(searchValue), 'i');
const filteredRows = platform.filter((row) => {
return Object.keys(row).some((field) => {
return searchRegex.test(row[field].toString());
});
});
setRows(filteredRows);
};
console.log(rows)
return (
<>
<Stack direction="row" alignItems="center" justifyContent='space-between' gap={1}>
<Stack direction="row" alignItems="center" gap={1}>
<RuleIcon sx={{ color: "text.secondary" }} />
<Typography sx={{ fontSize: 16, fontWeight: 'bold' }} color="text.secondary" gutterBottom>
{title}
</Typography></Stack>
<Box sx={{ flexDirection: 'column' }}>
<TextField
variant="outlined"
size='small'
value={searchText}
onChange={(e) => { setSearchText(e.target.value); requestSearch(e.target.value) }}
placeholder="Search..."
InputProps={{
startAdornment: <SearchIcon fontSize="small" color="action" />,
endAdornment: (
<IconButton
title="Clear"
aria-label="Clear"
size="small"
style={{ visibility: searchText ? 'visible' : 'hidden', borderRadius: "57%", paddingRight: "1px", margin: "0", fontSize: "1.25rem" }}
onClick={(e) => { setSearchText(''); setRows(platform) }}
>
<ClearIcon fontSize="small" color="action" />
</IconButton>
),
}}
sx={{
width: { xs: 1, sm: 'auto' }, m: (theme) => theme.spacing(1, 0.5, 1.5),
'& .MuiSvgIcon-root': {
mr: 0.5,
},
'& .MuiInput-underline:before': {
borderBottom: 1,
borderColor: 'divider',
},
}}
/>
</Box>
</Stack>
<div style={{ height: 250, width: '100%' }}>
<DataGrid
disableColumnMenu
rows={Rows}
columns={columns}
pageSize={10}
rowsPerPageOptions={[10]}
/>
</div>
</>
);
}
export default DataGridHelper
this is the data I'm getting initially
first of all, your code is so dirty :), i cant test your code cause its have your rest API and you don't name consoles, i just understand which one is result of axios, but i think your mistake is on useEffect depandecies in DataGridHelper you must write rows in it, and second maybe in useEffect when you get data in rest API you might write if condition for try in axios tell that if(!!result.data.data) then do that i think it must your problem
useEffect(() => {
setPlatform(rows);
setRows(rows);
}, [rows]);
and :
useEffect(() => {
axios.get('http://localhost:8006/api/v2/user/transactions').then(function (res) {
try {
if(!!res.data){
var result = res.data;
// console.log(result.data.data)
setTransactionData(result.data.data)
// setLoading(false);
}
}
catch (error) {
console.log(error)
}
})
}, [])
How can I make handleclick operation unique for each icon? For example when click to plus icon, color of all changes to green. But I want only plus icon to change into green.
const [isActive, setIsActive] = useState(false);
const handleClick = () => {
setIsActive((current) => !current);
};
return (
<div className="list-icons">
<FaPlus
className="plus-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
<FaCheck
className="check-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
<FaHeart
className="heart-icon"
style={{
color: isActive ? "green" : "",
}}
onClick={handleClick}
/>
</div>
)
The best way to do that is that you should create an array of object for your icons.
For example
const [icons, setIcons] = useState([
{
id: 1,
icon: FaPlus,
className:"plus-icon",
isActive: false,
},
{
id: 2,
icon: FaCheck,
className:"check-icon",
isActive: false,
},
{
id: 3,
icon: FaHeart,
className:"heart-icon",
isActive: false,
},
]);
const handleClick = (id: number) => {
const newIcons = icons.map((icon) => {
if(icon.id === id) {
return {
...icon,
isActive: !icon.isActive,
}
}
return icon;
});
setIcons(newIcons);
};
return (
<div className="list-icons">
{icons.map((icon) => {
const Icon = icon.icon
return (
(
<Icon
className={icon.className}
style={{
color: icon.isActive ? "green" : "",
}}
onClick={() => handleClick(icon.id}
/>
)
})
</div>
)
You should use an array of boolean:
const [isActive, setIsActive] = useState([false, false, false]);
const handleClick = (index) => {
setIsActive((current) => {
current[index] = !current[index];
return current;
});
};
return (
<div className="list-icons">
<FaPlus
className="plus-icon"
style={{
color: isActive[0] ? "green" : "",
}}
onClick={() => handleClick(0)}
/>
<FaCheck
className="check-icon"
style={{
color: isActive[1] ? "green" : "",
}}
onClick={() => handleClick(1)}
/>
<FaHeart
className="heart-icon"
style={{
color: isActive[2] ? "green" : "",
}}
onClick={() => handleClick(2)}
/>
</div>
)
const icons = ['plus', 'check', 'heart'];
const components = [<FaPlus />, <FaCheck />, <FaHeart />];
const [activeIcons, setActiveIcons] = useState(icons.map(() => false));
const onActiveToggle = (index) => {
setActiveIcons(prev => {
prev[index] = !prev[index];
return prev;
});
}
const iconProps = useMemo(() => {
return icons.map((icon, index) => ({
className: `${icon}-icon`,
style: {{ color: activeIcons[index] ? 'green': 'black' }},
onClick: () => onActiveToggle(index)
})
}, [activeIcons]);
return (
<>
{components.map((Component, index) => (
<Component {...iconProps[index]}/>
))}
</>
);
I am trying to make a search input that will filter by the name user will input. I have two components one is having the search input (app.js) and the other is having the table(table.js).
I am able to get the current value of the search input (app.js) but when trying to pass it as a props in the table (table.js) it's giving an error.
I am new to react but from my understanding, I think I'm having issues with passing the useState as a props.
1. Code for search input (app.js)
I used onChange event as to get the current value when the input field change.
<div className="search">
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search..."
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
onChange={getSearchTerm}
/>
</div>
</div>
getSearchTerm function to get current input value
const [searchTerm, setSearchTerm] = useState("");
const getSearchTerm = (event) => {
const searchWord = event.target.value;
console.log(searchWord);
setSearchTerm(searchWord)
}
2. Table (app.js) passing the props
passing the props in the filter function. So can get filterd when a input would be entered in search input.
export default function EnhancedTable(props) {
console.log("these r props for table component", props);
<TableBody>
{data
.filter((item) => {
if (props.searchTerm == "") {
return item;
} else if (item.clientName.toLowerCase().includes(props.searchTerm.toLowerCase())) {
return item;
}
})
.map((item, index) => {
return (
<TableRow
hover
role="checkbox"
tabIndex={-1}
>
<TableCell padding="checkbox">
<Checkbox
/>
</TableCell>
<TableCell component="th" scope="row" padding="none">{item.clientName}</TableCell>
<TableCell align="right">{item.clientEmail}</TableCell>
<TableCell align="right">{item.clientWorkPhone}</TableCell>
<TableCell align="right">{item.clientIndustry}</TableCell>
<TableCell align="right">{item.tenantId}</TableCell>
<TableCell align="right">{item.clientWebsite}</TableCell>
<TableCell align="right"><Button style={{ backgroundColor: 'transparent', color: '#5900B4' }} variant="outlined" color="primary" href="#outlined-buttons" >{<CreateIcon />}</Button>
</TableCell>
</TableRow>
)
})}
</TableBody>
3. Error getting
[The error I'm getting is here][1]
4. Full Search input (app.js) file for more clarity
function App() {
const [searchTerm, setSearchTerm] = useState("");
const classes = useStyles();
const getSearchTerm = (event) => {
//console.log(inputEl.current.value);
const searchWord = event.target.value;
console.log(searchWord);
setSearchTerm(searchWord)
}
return (
<div className="App">
<div className="wrapper">
<div className="container-table">
<div className="head">
<h5 className='management'>MANAGEMENT</h5>
<div className="head-middle">
<h2>Clients</h2>
<div className="button-collection">
<Button style={{ backgroundColor: '#5900B4', color: '#FFFFFF', fontSize: '15px', fontWeight: '900', width: '206px', height: '42px' }}
variant="contained"
className='add-collection-btn'
startIcon={<AddIcon />}
>
New Collection
</Button>
</div>
</div>
<div className="head-bottom">
<div className="head-button">
<div className="search">
<div className={classes.search}>
<div className={classes.searchIcon}>
<SearchIcon />
</div>
<InputBase
placeholder="Search..."
classes={{
root: classes.inputRoot,
input: classes.inputInput,
}}
onChange={getSearchTerm}
/>
</div>
</div>
<Button style={{ backgroundColor: 'white', color: 'black', width: '100px', height: '40px', marginLeft: '20px', marginRight: '20px' }} variant="contained">Search</Button>
<Button style={{ backgroundColor: 'white', color: 'black', width: '100px', height: '40px' }} variant="contained">Clear</Button>
</div>
<Button style={{
backgroundColor: 'transparent', color: '#5900B4', width: '206px', height: '42px', borderColor: '#5900B4', fontSize: '15px', fontWeight: '900'
}} variant="outlined" color="primary"
startIcon={<FilterListIcon />}
>
SHOW FILTER
</Button>
</div>
<div className="table">
<EnhancedTable
onChange={setSearchTerm}
/>
</div>
</div>
</div>
</div>
</div>
);
}
export default App;
5. Full table (table.js) file for clarity
const headCells = [
{ id: 'name', numeric: false, disablePadding: true, label: 'Client Name' },
{ id: 'email', numeric: true, disablePadding: false, label: 'Email' },
{ id: 'phone', numeric: true, disablePadding: false, label: 'Phone' },
{ id: 'industry', numeric: true, disablePadding: false, label: 'Industry' },
{ id: 'contact', numeric: true, disablePadding: false, label: 'Point of Contact' },
{ id: 'website', numeric: true, disablePadding: false, label: 'Website' },
{ id: 'btn-icon', numeric: true, disablePadding: false, label: '' },
];
function EnhancedTableHead(props) {
const { classes, onSelectAllClick, order, orderBy, numSelected, rowCount } = props;
return (
<TableHead>
<TableRow style={{ backgroundColor: '#F5F6F8', height: '120px' }}>
<TableCell padding="checkbox">
<Checkbox
indeterminate={numSelected > 0 && numSelected < rowCount}
checked={rowCount > 0 && numSelected === rowCount}
onChange={onSelectAllClick}
inputProps={{ 'aria-label': 'select all desserts' }}
/>
</TableCell>
{headCells.map((headCell) => (
<TableCell
key={headCell.id}
align={headCell.numeric ? 'right' : 'left'}
padding={headCell.disablePadding ? 'none' : 'normal'}
>
{headCell.label}
</TableCell>
))}
</TableRow>
</TableHead>
);
}
EnhancedTableHead.propTypes = {
classes: PropTypes.object.isRequired,
numSelected: PropTypes.number.isRequired,
order: PropTypes.oneOf(['asc', 'desc']).isRequired,
orderBy: PropTypes.string.isRequired,
};
const useToolbarStyles = makeStyles((theme) => ({
root: {
paddingLeft: theme.spacing(2),
paddingRight: theme.spacing(1),
},
highlight:
theme.palette.type === 'light'
? {
color: theme.palette.secondary.main,
backgroundColor: lighten(theme.palette.secondary.light, 0.85),
}
: {
color: theme.palette.text.primary,
backgroundColor: theme.palette.secondary.dark,
},
title: {
flex: '1 1 100%',
},
}));
const EnhancedTableToolbar = (props) => {
const classes = useToolbarStyles();
return (
<Toolbar>
{
<Typography className={classes.title} variant="h6" id="tableTitle" component="div">
Clients
</Typography>
}
</Toolbar>
);
};
EnhancedTableToolbar.propTypes = {
numSelected: PropTypes.number.isRequired,
};
const useStyles = makeStyles((theme) => ({
root: {
width: '100%',
},
paper: {
width: '100%',
marginBottom: theme.spacing(2),
},
table: {
minWidth: 750,
},
visuallyHidden: {
border: 0,
clip: 'rect(0 0 0 0)',
height: 1,
margin: -1,
overflow: 'hidden',
padding: 0,
position: 'absolute',
top: 20,
width: 1,
},
}));
export default function EnhancedTable(props) {
console.log("these r props for table component", props);
const classes = useStyles();
const [order, setOrder] = React.useState('asc');
const [orderBy, setOrderBy] = React.useState('calories');
const [selected, setSelected] = React.useState([]);
const [page, setPage] = React.useState(0);
const [dense, setDense] = React.useState(false);
const [rowsPerPage, setRowsPerPage] = React.useState(5);
const isSelected = (name) => selected.indexOf(name) !== -1;
const [data, setData] = useState([]);
const getData = async () => {
try {
const data = await axios.get("something");
setData(data.data);
} catch (e) {
console.log("this is error for fetching data", e)
}
};
useEffect(() => {
getData();
}, [])
return (
<div className={classes.root}>
<Paper className={classes.paper}>
<EnhancedTableToolbar numSelected={selected.length} />
<TableContainer>
<Table
className={classes.table}
aria-labelledby="tableTitle"
size={dense ? 'small' : 'medium'}
aria-label="enhanced table"
>
<EnhancedTableHead
classes={classes}
numSelected={selected.length}
order={order}
orderBy={orderBy}
/>
<TableBody>
{data
/*.filter((item) => {
if (searchTerm == "") {
return item;
} else if (item.clientName.toLowerCase().includes(searchTerm.toLowerCase())) {
return item;
}
})*/
.map((item, index) => {
return (
<TableRow
hover
role="checkbox"
tabIndex={-1}
>
<TableCell padding="checkbox">
<Checkbox
/>
</TableCell>
<TableCell component="th" scope="row" padding="none">{item.clientName}</TableCell>
<TableCell align="right">{item.clientEmail}</TableCell>
<TableCell align="right">{item.clientWorkPhone}</TableCell>
<TableCell align="right">{item.clientIndustry}</TableCell>
<TableCell align="right">{item.tenantId}</TableCell>
<TableCell align="right">{item.clientWebsite}</TableCell>
<TableCell align="right"><Button style={{ backgroundColor: 'transparent', color: '#5900B4' }} variant="outlined" color="primary" href="#outlined-buttons" >{<CreateIcon />}</Button>
</TableCell>
</TableRow>
)
})}
</TableBody>
</Table>
</TableContainer>
</Paper>
</div>
);
}
The issue is that searchTerm is not within scope of your component so this line...
item.clientName.toLowerCase().includes(searchTerm.toLowerCase())
throws the error you're seeing
Cannot read property 'toLowerCase' of undefined
You need to pass in the required props to your component.
<EnhancedTable searchTerm={searchTerm} />
This is also a perfect opportunity to use React's useMemo hook to produce the filtered results
const { searchTerm } = props // extract searchTerm from props
const filtered = useMemo(() => {
if (!searchTerm) {
return data
}
const term = searchTerm.toLowerCase()
return data.filter(({ clientName }) =>
clientName.toLowerCase().includes(term))
}, [ data, searchTerm ])
Now you can just use filtered in place of data in your return value
<TableBody>
{filtered.map((item, index) => {
// etc
})}
</TableBody>
i'm new to react native i'm implementing the signup through firebase phone number otp .
my code is:
constructor(props) {
super(props);
this.unsubscribe = null;
this.state = {
user: null,
message: '',
codeInput: '',
phoneNumber: '+91',
confirmResult: null,
};
}
componentDidMount() {
this.unsubscribe = firebase.auth().onAuthStateChanged((user) => {
if (user) {
this.setState({ user: user.toJSON() });
} else {
// User has been signed out, reset the state
this.setState({
user: null,
message: '',
codeInput: '',
phoneNumber: '+91',
confirmResult: null,
});
}
});
}
componentWillUnmount() {
if (this.unsubscribe) this.unsubscribe();
}
signIn = () => {
const { phoneNumber } = this.state;
this.setState({ message: 'Sending code ...' });
firebase.auth().signInWithPhoneNumber(phoneNumber)
.then(confirmResult => this.setState({ confirmResult, message: 'Code has been sent!' }))
.catch(error => this.setState({ message: `Sign In With Phone Number Error:
${error.message}` }));
};
confirmCode = () => {
const { codeInput, confirmResult } = this.state;
if (confirmResult && codeInput.length) {
confirmResult.confirm(codeInput)
.then((user) => {
this.setState({ message: 'Code Confirmed!' });
})
.catch(error => this.setState({ message: `Code Confirm Error: ${error.message}` }));
}
};
signOut = () => {
firebase.auth().signOut();
}
renderPhoneNumberInput() {
const { phoneNumber } = this.state;
return (
<View style={{ padding: 25 }}>
<Text>Enter phone number:</Text>
<TextInput
autoFocus
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
onChangeText={value => this.setState({ phoneNumber: value })}
placeholder={'Phone number ... '}
value={phoneNumber}
/>
<Button title="Sign In" color="green" onPress={this.signIn} />
</View>
);
}
renderMessage() {
const { message } = this.state;
if (!message.length) return null;
return (
<Text style={{ padding: 5, backgroundColor: '#000', color: '#fff' }}>{message}</Text>
);
}
renderVerificationCodeInput() {
const { codeInput } = this.state;
return (
<View style={{ marginTop: 25, padding: 25 }}>
<Text>Enter verification code below:</Text>
<TextInput
autoFocus
style={{ height: 40, marginTop: 15, marginBottom: 15 }}
onChangeText={value => this.setState({ codeInput: value })}
placeholder={'Code ... '}
value={codeInput}
/>
<Button title="Confirm Code" color="#841584" onPress={this.confirmCode} />
</View>
);
}
render() {
const { user, confirmResult } = this.state;
return (
<View style={{ flex: 1 }}>
{!user && !confirmResult && this.renderPhoneNumberInput()}
{this.renderMessage()}
{!user && confirmResult && this.renderVerificationCodeInput()}
{user && (
<View
style={{
padding: 15,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#77dd77',
flex: 1,
}}
>
<Image source={{ uri: successImageUri }} style={{ width: 100, height: 100,
marginBottom: 25 }} />
<Text style={{ fontSize: 25 }}>Signed In!</Text>
<Text>{JSON.stringify(user)}</Text>
<Button title="Sign Out" color="red" onPress={this.signOut} />
</View>
)}
</View>
);
}
}
But while implementing it is saying to pass two arugument but i don't want recaptcha i just want otp. while implementing the signinwithphonenumber i'm getting this error.signInWithPhoneNumber failed: Expected 2 arguments but got 1. is it compulsion to add 2nd argument. Any help will be appriciated.