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>
);
}
Related
I never see this error before.
I found where error is occurred.
However, i don't know why it occurred.
there is no return code before setState. If i use {imgPath} only, there is no error occurred.
What I do
I create another state for test. If i use state into component, error occurred. It is line 86.
this is my full code
I delete import component code
import { FC, useRef, useState } from 'react';
import styled from 'styled-components';
import { 팀정보변경, uploadLogo } from 'controller/modifyTeam';
import { getTeamInformation } from 'controller/team';
// module
import { useSnackbarStore } from 'module/store/snackbar';
import { useTeamStore } from 'module/store/team';
const Form: FC<Props> = ({ teamname, timezone, id, name, url }) => {
const { updateTeam } = useTeamStore();
const { pushSnackbar } = useSnackbarStore();
const [isEmpty, setIsEmpty] = useState<boolean>(false);
const [imgPath, setImgPath] = useState<string>('');
const [test, setTest] = useState<string>('');
// ref
const teamNameRef = useRef<HTMLInputElement>(null);
const timeLineRef = useRef<HTMLInputElement>(null);
const imgRef = useRef<HTMLInputElement>(null);
const widthSX = (width: string) =>
useSX({
width: `${width}`,
});
const paddingSX = useSX({
padding: '4px 12px !important',
});
// formData
const onClickUploadImage: () => void = () => imgRef?.current?.click();
const onDeleteImage: () => void = () => setImgPath('');
const updateTeamInformation: () => void = async () => {
const res = await getTeamInformation();
updateTeam(res.data.result);
};
const onSubmit: () => void = async () => {
const timeline = timeLineRef.current.value.slice(4, 10).replaceAll(':', '');
const res = await 팀정보변경(teamNameRef.current.value, timeline, imgPath, id);
if (res.data.msg === 'created') {
await updateTeamInformation();
pushSnackbar({
id: 'teamworthchanged',
type: 'Info',
title: `${t('snackbar.team_worth_changed')}`,
});
}
};
const onChangeImage: (event: any) => void = async (event: any) => {
const formData = new FormData();
formData.append('logo', event.target.files[0]);
const res = await uploadLogo(formData);
setImgPath(res.data.result.path);
};
return (
<>
<SideBar index={1} />
<Container>
<Contents xs={12} sm={8} md={6} lg={5}>
<Font className="h5">{t('nav.menu.settings.basic')}</Font>
<WhiteSpace />
<Grid container item xs={12} direction="column">
{/* 기본설정 */}
<Font className="body-2">{t('settings.basic.profile.heading')}</Font>
<Font className="caption">{t('settings.basic.profile.sub')}</Font>
<Grid container flexWrap="wrap" justifyContent="space-between">
<WhiteSpace />
<Grid xs={4} item container alignItems="center">
{imgPath === '' ? (
url === null ? (
<DefaultImg
container
justifyContent="center"
alignItems="center"
sx={widthSX('80px')}
>
{name?.slice(0, 1)}
</DefaultImg>
) : (
<TeamIcon src={url} alt="팀 로고" />
)
) : (
<TeamIcon src={imgPath} alt={'팀 로고'} />
)}
</Grid>
{/* 이미지 업로드 */}
<Grid container item xs="auto" alignItems="center" flexWrap="wrap" sx={UploadImageSX}>
<label htmlFor="contained-button-file">
<MuiButton
content={
<Grid container alignItems="center">
<Grid item>{t('btn.upload_image')}</Grid>
<Grid item>
<MdiIcon width={16} height={16} src="/icons/upload/ic_upload_white.svg" />
</Grid>
</Grid>
}
size="small"
type="contained"
sx={paddingSX}
onClick={onClickUploadImage}
/>
</label>
<ImageInput
accept="image/*"
id="contained-button-file"
onChange={onChangeImage}
type="file"
ref={imgRef}
/>
{/* 이미지 삭제 버튼 */}
<MuiButton
content={t('btn.remove')}
size="small"
color={palette.gray3}
sx={paddingSX}
onClick={onDeleteImage}
/>
</Grid>
</Grid>
</Grid>
<WhiteSpace />
{/* 팀이름 INPUT */}
<Input
label="common.team_name"
isEmpty={isEmpty}
setIsEmpty={setIsEmpty}
ref={teamNameRef}
value={teamname}
/>
<WhiteSpace />
{/* 시간대 */}
<Grid container item xs={12} direction="column">
<Font className="body-2">{t('settings.basic.timezone.heading')}</Font>
<Font className="caption">{t('settings.basic.timezone.sub')}</Font>
</Grid>
<WhiteSpace />
{/* <TimeLine currentTime={timezone} time={time} setTime={setTime} /> */}
<Timeline ref={timeLineRef} time={timezone} />
<WhiteSpace />
<WhiteSpace />
<MuiButton
content={t('btn.save_changes')}
sx={widthSX('100%')}
type="contained"
onClick={onSubmit}
/>
</Contents>
</Container>
</>
);
};
export default Form;
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;
Hello I'm trying to create that I had three cards in a row right now one after the other
Can't find a solution
It's a complement
const Posts = ({ setCurrentId }) => {
const fuzzySearch = (list, searchValue) => {
let buf = ".*" + searchValue.replace(/(.)/g, "$1.*").toLowerCase();
var reg = new RegExp(buf);
let newList = list.filter(function (e) {
return reg.test(e.title.toLowerCase()&&e.message);
});
return newList;
};
const [searchValue, setSearchValue] = useState("");
const posts = useSelector((state) => state.posts);
const classes = useStyles();
const [pageNumber, setPageNumber] = useState(1);
const [buttonnext, setbuttonnext] = useState(false);
const [prebutton, setprebutton] = useState(true);
const limit=8;
const [startIndex,setstartIndex] = useState();
const [endIndex,setendIndex] = useState();
useEffect(()=>{
setstartIndex((pageNumber-1)*limit)
setendIndex(pageNumber*limit)
console.log(startIndex)
console.log(endIndex)
},[posts,pageNumber])
const Next = ()=>{
if(pageNumber === (Math.floor((posts.length+limit -1)/limit))){
setbuttonnext(true)
}else{
setPageNumber(pageNumber+1)
setprebutton(false)
}
}
const Previous = () =>{
if(pageNumber === 1){
setprebutton(true)
}else{
setPageNumber(pageNumber-1)
setbuttonnext(false)
}
}
return(
!posts.length ? <CircularProgress /> : <>
< >
<AppBar className={classes.appBar} position="static" color="inherit">
<Typography className={classes.heading} variant="h2" >קבוצות אחרונות</Typography>
<Paper component="form" className={classes.root}>
<IconButton className={classes.iconButton} aria-label="menu">
</IconButton>
<InputBase
className={classes.input}
placeholder="חיפוש "
inputProps={{ 'aria-label': 'search ' }}
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
/>
<IconButton className={classes.iconButton} aria-label="search">
<SearchIcon />
</IconButton>
<Divider className={classes.divider} orientation="vertical" />
</Paper>
</AppBar>
<ol>
{fuzzySearch(posts, searchValue).slice(startIndex,endIndex).map((d) => (
<Grid key={d._id} item xs={10} sm={6} md={6}>
<Grow in>
<Post post={d} setCurrentId={setCurrentId} />
</Grow>
</Grid>) )}
</ol>
</>
<Grid className={classes.container} container alignItems="stretch" spacing={3}>
<Grid container direction="row-reverse"justifyContent="center"alignItems="flex-end" >
<>
<button className={classes.button} onClick={Next}>הבא</button>
<p className={classes.numText}>{ pageNumber}</p>
<Button className={classes.button} onClick={Previous}>אחורה</Button>
</>
</Grid>
</Grid></>
)
};
export default Posts;
Then called to app in app.js Grid in shape
return (
<Container maxWidth="lg" >
<Grow in>
<Container>
<Posts setCurrentId={setCurrentId} />
</Container>
</Grow>
</Container>
);
};
export default App;
I would to create a grid that I had three in a row
I don't know what you are trying to achieve, but I assume that you are trying to display 3 cards in a row. The idea is that Material-UI is using flexbox, and they are divided into 12 equal columns.
<Grid spacing={2}>
// Define grid for card items
{
data.map((dataItem) => (
<Grid key={dataItem.id}>
// ... items inside
</Grid>
))
}
</Grid>
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>
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.