Can you pass different Material-ui icons as props? - reactjs

I am wondering how I would add different Icons? This is what I have so far but the icon does not show in my UI?
my props thought that would work
When I add the Facebook button it doesn't show like it does on the button I added
const Item = ({ name = 'Item Name', tags = [] }, icon) => {
return (
<Grid item xs={12} spacing={2}>
<Paper elevation={6}>
<Grid container justifyContent="flex-start" spacing={3}>
<Grid item xs={12}>
{/*Notice the name is in {} since it is a variable*/}
<h1>{name}</h1>
{icon}
<div>{icon}</div>
</Grid>
<Grid item>
{tags.map((tag, idx) => {
return <Chip key={idx} label={tag} color={'secondary'} />;
})}
</Grid>
<Grid item>
<Button endIcon={<FacebookIcon />} color="primary" variant="contained">
Button 1
</Button>
<Button color="secondary" variant="contained">
Button 2
</Button>
</Grid>
</Grid>
</Paper>
</Grid>
);
};
const MyView = () => {
return (
<Widget>
<Grid container spacing={4}>
<Item icon={<FacebookIcon />} name={jsonData.name} tags={jsonData.tags} />
<Item name="test paper" tag={'chip2'}></Item>
<Item name={jsonData.name} tags={jsonData.tags} />
</Grid>
</Widget>
);
};
export default MyView;

your mistake is there const Item = ({name="Item Name", tags=[],icon} ) => {
you must import icon from the props object not like a parameter. you should notice that Item was not used like a function with parameter and it is a react component :
import FacebookOutlinedIcon from '#mui/icons-material/FacebookOutlined';
const Item = ({name="Item Name", tags=[],icon} ) => {
return (
<>
<Grid item xs={12} spacing={2}>
<Paper elevation={6}>
<Grid container justifyContent="flex-start" spacing={3}>
<Grid item xs={12}>
{/*Notice the name is in {} since it is a variable*/}
<h1>{name}</h1>
{icon}
<div>{icon}</div>
</Grid>
</Grid>
</Paper>
</Grid>
</>
)
}
const Add = (props) => {
return (
<Item icon={<FacebookOutlinedIcon/>} name="test" tags={[]}/>
);
};
export default Add;

Related

Open Accordion only on click of the accordion

enter image description here
when i click on the checkbox it opens the accordion.
what can i do to prevent the accordion from opening when i click on the checkbox.
is there any style for this? or what should i do to make it open
export const FinancialAccordions: React.FC<Props> = ({ control, operation, index }) => {
const [expanded, setExpanded] = useState('panel_0');
const handleChangeExpanded = useCallback(
(panel: string) => (event, newExpanded) => {
setExpanded(newExpanded ? panel : false);
},
[expanded],
);
return (
<>
<Accordion key={operation.expenseId} onChange={handleChangeExpanded(`panel_${operation.expenseId}`)}>
<AccordionSummary expandIcon={<SvgArrowFinancial />}>
<Grid css={pl(12)} container justifyContent="flex-start" alignItems="center">
<Grid item xs={0.3}>
<Controller
control={control}
name={`selections.${index}`}
render={({ field: { value, onChange } }) => (
<FormControlLabel
value={value}
onChange={(e, checked) => onChange(checked)}
css={labelTextCSS}
control={<Checkbox />}
label=""
/>
)}
/>
</Grid>
</Grid>
</AccordionSummary>
<AccordionDetails>
<Grid container justifyContent="space-between" flexDirection="column">
<Grid item xs={11.35}>
<Grid container justifyContent="center" alignItems="start">
<Grid item xs={5.7}></Grid>
<Grid item xs={3.8}>
<Typography css={operationsChildDataCSS}>На сумму {operation.money} в том числе НДС 18%</Typography>
</Grid>
<Grid item xs={2.14}>
<Typography css={[operationsChildDataCSS, textRightCSS]}>По счёту</Typography>
</Grid>
</Grid>
</Grid>
<Grid></Grid>
</Grid>
</AccordionDetails>
</Accordion>
</>
);

TypeError: Cannot read properties of undefined (reading 'length')

I am following a youtube tutorial and we returned conditional HTML elements if post.length is 0 or not but I get "TypeError: Cannot read properties of undefined (reading 'length')"
const Posts = () => {
const posts = useSelector((state) => state.posts)
return (
!posts.length ? <CircularProgress /> : (
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
{posts.map((post) => (
<Grid key={post._id} item xs={12} sm={6}>
<Post post={post}/>
</Grid>
))}
</Grid>
)
);
};
So I tried to use the following traditional if statement to see if I made a syntax error but seems like it wasn't the case
if (!posts.length) {
return <CircularProgress />
} else {
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
{posts.map((post) => (
<Grid key={post._id} item xs={12} sm={6}>
<Post post={post}/>
</Grid>
))}
</Grid>
}
First of all make sure you have posts already defined in the component with a console log :
console.log(posts);
If it is defined then you need to change the posts.length code to this code :
if (posts && !posts.length) {
return <CircularProgress />
} else {
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
{posts && posts.map((post) => (
<Grid key={post._id} item xs={12} sm={6}>
<Post post={post}/>
</Grid>
))}
</Grid>
}
This way we are saying that get the length of the posts only when it gets available in the component .

Material UI: best way to set elements side by side

I'm currently using Material UI to style an ecommerce project. I'm trying to figure out how to make all of the elements (Typography, Buttons) display side by side in a row instead of vertically.
Is there a way to do this simply with material UI? Should I add CSS? I previously tried adding each element to a Grid item within a Container, it kind of worked (couldn't center), but doesn't seem like the right approach for this scenario.
If you see my screenshot below, I'm trying to set "T-Shirt Twilight", the image, "$49.99", the quantity input buttons and "Remove" side by side horizontally.
Elements I'm trying to set side by side:
<div className="App">
{products.map((item, index) => (
<Grid container item xs={12}>
<Grid item xs={1} />
<Grid item xs={10}>
<Grid item xs={12} container key={item.id}>
<Grid item xs={1} />
<Grid item xs={10}>
<Typography>{item.title}</Typography>
<img src={require(`../images/${item.image}`)} className={classes.productImage}></img>
<Typography>${(item.quantity * item.price).toFixed(2)}</Typography>
<ButtonGroup size="small">
<Button type="button" onClick={item.quantity > 1 ? () => decreaseQuantity(index) : null}>-</Button>
<Button>{item.quantity}</Button>
<Button type="button" onClick={() => increaseQuantity(index)}>+</Button>
</ButtonGroup>
<Button
onClick={() => removeItem(index)}>
Remove
</Button>
</Grid>
<Grid item xs={1} />
</Grid>
</Grid>
<Grid item xs={1} />
</Grid>
))}
</div>
Screenshot for reference:
Full code:
import React, { useState, useEffect } from 'react';
import './../App.css';
import * as ReactBootStrap from 'react-bootstrap';
import {Link} from 'react-router-dom';
import { getQuantity, getTotal } from '../helpers/helperTools';
import {Grid, Typography,useMediaQuery, useTheme, Container, Button, ButtonGroup} from '#material-ui/core';
import {makeStyles} from '#material-ui/core/styles';
const useStyles = makeStyles((theme) => ({
productImage: {
maxWidth: '20%'
}
}))
function Cart({ setQty: setParentQty }) {
const classes = useStyles();
const [products, setProducts] = useState([]);
function updateQty(products){
/* var holder = 0;
products.forEach((a, b) => {
holder = holder + a.quantity
})*/
// setQty({quantity: holder})
// localStorage.setItem('quantity', JSON.stringify({ quantity: newQty }))
setParentQty({ quantity: getQuantity(products) });
}
useEffect(function() {
const storageItems = JSON.parse(localStorage.getItem('product'));
const products = storageItems || [];
setProducts(products);
updateQty(products);
}, []);
function decreaseQuantity(index) {
if (products[index]){
const newProducts = products.map((a, b) => {
if (b === index) return {...a, quantity: a.quantity - 1}
else return a
});
setProducts(newProducts);
localStorage.setItem('product', JSON.stringify(newProducts))
updateQty(newProducts)
}
}
function increaseQuantity(index) {
if (!products[index]) return;
const newProducts = products.map((a, b) => {
if (b === index) return {...a, quantity: a.quantity + 1}
else return a
})
setProducts(newProducts)
localStorage.setItem('product', JSON.stringify(newProducts))
updateQty(newProducts);
}
function removeItem(index){
const product = products[index];
if (!product) return;
const newProducts = products.filter((v, z) => z !== index);
setProducts(newProducts);
localStorage.setItem('product', JSON.stringify(newProducts));
updateQty(newProducts);
}
if (products.length === 0) {
return (
<div className="App">
<p>
Cart Empty
</p>
<Link to={`/`}>
<p>Continue shopping</p>
</Link>
</div>)
}
return (
<div className="App">
{products.map((item, index) => (
<Grid container item xs={12}>
<Grid item xs={1} />
<Grid item xs={10}>
<Grid item xs={12} container key={item.id}>
<Grid item xs={1} />
<Grid item xs={10}>
<Typography>{item.title}</Typography>
<img src={require(`../images/${item.image}`)} className={classes.productImage}></img>
<Typography>${(item.quantity * item.price).toFixed(2)}</Typography>
<ButtonGroup size="small">
<Button type="button" onClick={item.quantity > 1 ? () => decreaseQuantity(index) : null}>-</Button>
<Button>{item.quantity}</Button>
<Button type="button" onClick={() => increaseQuantity(index)}>+</Button>
</ButtonGroup>
<Button
onClick={() => removeItem(index)}>
Remove
</Button>
</Grid>
<Grid item xs={1} />
</Grid>
</Grid>
<Grid item xs={1} />
</Grid>
))}
</div>
);
}
export default Cart;
Just use inline style for it. I also removed some unnecessary grid items. May be you want to grid more about breakpoints in Grid. Working CodeSandBox
<Grid container>
<Grid item xs={1} />
<Grid item xs={10} style={{ display: "flex", gap: "1rem" }}>
<Typography>{item.title}</Typography>
<img src={item.image} className={classes.productImage}></img>
<Typography>${(item.quantity * item.price).toFixed(2)}</Typography>
<ButtonGroup size="small">
<Button
type="button"
onClick={
item.quantity > 1 ? () => decreaseQuantity(index) : null
}
>
-
</Button>
<Button>{item.quantity}</Button>
<Button type="button" onClick={() => increaseQuantity(index)}>
+
</Button>
</ButtonGroup>
<Button onClick={() => removeItem(index)}>Remove</Button>
</Grid>
<Grid item xs={1} />
</Grid>

Reactjs tests (react testing library)

Can anyone help with how I can test the component below? I am using the testing-library / react library and am having difficulties.
export default function BodyCardConfirmacaoSeguranca({ email, celular }) {
const [selectedCard, setSelectedCard] = useState(null);
const handleSelectCard = (value) => {
if (value === selectedCard) {
setSelectedCard(null);
} else {
setSelectedCard(value);
}
};
return (
<>
<CardEnvioCod
data-testid="email"
tipoEnvio="email"
data={email}
handleSelectCard={() => handleSelectCard('email')}
selectedCard={selectedCard}
/>
<CardEnvioCod
data-testid="sms"
tipoEnvio="sms"
data={telefone(celular)}
handleSelectCard={() => handleSelectCard('sms')}
selectedCard={selectedCard}
/>
</>
);
}
I'm trying something like this:
it('', () => {
const { findByTestId } = Render(
<ThemeProvider theme={AppTheme}>
<BodyCardConfirmacaoSeguranca />
</ThemeProvider>,
);
const email = findByTestId('email');
const sms = findByTestId('sms');
fireEvent.change(email, { selectedCard: 'email' });
fireEvent.change(sms, { selectedCard: 'sms' });
});
I need to test the handleSelectCard function and its call on the components
below follows the code, it has not yet been tested. It is used inside the , can I be doing the test in the wrong place too? I'm lost
export default function CardEnvioCod({
tipoEnvio,
data,
handleSelectCard,
selectedCard,
}) {
const classes = useStyles();
const selected = selectedCard === tipoEnvio;
const icon =
tipoEnvio === TIPO_ENVIO.EMAIL ? (
<EmailOutlined
className={clsx(classes.icon, selected && classes.selected)}
/>
) : (
<PhoneAndroidOutlinedIcon
className={clsx(classes.icon, selected && classes.selected)}
/>
);
const text =
tipoEnvio === TIPO_ENVIO.EMAIL
? 'Enviar por e-mail:'
: 'Enviar por SMS:';
useEffect(() => {}, []);
return (
<Grid container justify="center" className={classes.container}>
<Grid
item
component={Paper}
variant="outlined"
lg={7}
xs={12}
square
elevation={0}
className={clsx(classes.root, selected && classes.selected)}
onClick={handleSelectCard}
>
<Grid container justify="space-between" alignItems="center">
<Grid item lg={1} xs={2}>
<Icon>{icon}</Icon>
</Grid>
<Grid item xs={8}>
<Grid container justify="flex-start" direction="column">
<Typography
className={clsx(
classes.titleCard,
selected && classes.selected,
)}
>
{text}
</Typography>
<Typography
title={data}
className={classes.divData}
>
{data}
</Typography>
</Grid>
</Grid>
<Grid item lg={1} xs={2}>
<Grid container justify="flex-end">
{selected ? (
<CheckBoxIcon
fontSize="large"
cursor="pointer"
/>
) : (
<CheckBoxOutlineBlank
color="primary"
fontSize="large"
cursor="pointer"
/>
)}
</Grid>
</Grid>
</Grid>
</Grid>
</Grid>
);
}

How to use Checkbox from material-UI to toggle strikethrough on a todo list item

const Todo: React.FC<ITodoProps> = (props) => {
const [textInput, setTextInput] = useState('');
const {
addTodo,
userId,
todosForUser,
user,
} = props;
if (user == null) {
return (
<Grid
container={true}
direction='column'
wrap='nowrap'
>
<Grid
item={true}
>
<Typography
variant='h5'
>
INVALID USER
</Typography>
</Grid>
</Grid>
);
}
return (
<Grid
container={true}
direction='column'
wrap='nowrap'
>
<Grid
item={true}
>
<Typography
variant='h5'
>
TODOS FOR {user.get('name')}
</Typography>
</Grid>
<Grid
container={true}
item={true}
direction='column'
wrap='nowrap'
>
<Grid
item={true}
container={true}
alignItems='center'
>
<Grid
item={true}
>
<TextField
label='title'
value={textInput}
onChange={(e) => {
setTextInput(e.target.value);
}}
/>
</Grid>
<Grid
item={true}
>
<Button
variant='outlined'
onClick={
() => {
addTodo(
userId,
TodoFactory({
title: textInput,
}),
);
setTextInput('');
}
}
>
Add Todo
</Button>
</Grid>
</Grid>
{
todosForUser.map((todo, index) => {
return <Grid
key={index}
item={true}
>
Here is the Checkbox
<Checkbox>
</Checkbox>
Here is the target todo list
{todo.get('title')}
</Grid>;
})
}
</Grid>
</Grid>
);
}
I'm using material-UI, typescript, react, redux, saga, immutablejs.
Basically, it's a todo list and I'm struggling with how to do a line-through on a list item when the is toggled.
Here is how it looks
When checked
When unchecked
I couldn't get my head around how to use Checkbox with onClick with this stack. Help is greatly appreciated.
Thank you.
When I was trying to mark items as deleted (a strikethrough effect) I used the <del> tag in my list.
Example:
<ListItem key={"occasion-list-item-" + occasion.Id} button onClick={() => handleToggle(occasion)}>
{ occasion.Enabled ?
(
<ListItemText id={occasion.Id} primary={JSON.stringify(occasion.Enabled)} />
)
:
(
<del>
<ListItemText id={occasion.Id} primary={JSON.stringify(occasion.Enabled)} />
</del>
)
}
</ListItem>
Where occasion is a POJO like:
{
"Id" : <some sort of string guid>,
"Enabled" : true
}
You'd have a handler which would go and update the value Enabled in that item in your component state and then react will re-render your page. When it re-renders the page, Enabled is true so chooses the first code path.

Resources