ReactJS img not updating after API Call - reactjs

Im learning React right now and trying to wrap my head around why my other components updated the information but my img tag has not after the second API call.
Here's my code:
export default function LandingPage() {
const [zipcode, setZipCode] = useState('');
const [loading, setLoading] = useState(false);
const [weatherData, setWeatherData] = useState();
var [cityWeatherData, setCityWeatherData] = useState([]);
var [forecast, setForcast] = useState([]);
return(
<TextField
label='Zip Code'
value={zipcode}
onChange={(e) => { setZipCode(e.target.value) }} />
<Button
sx={{ ml: 3, backgroundColor: '#5F8FFF', color: 'white', '&:hover': { color: '#5F8FFF' } }}
onClick={ () => {
currentWeather(zipcode, apiKey)
.then( async (result) => {
setLoading(true);
await sevenDayWeather(result['coord']['lon'], result['coord']['lat'], apiKey)
.then( (response) => {
response['daily'].forEach( (day) => {
console.log('day forecast: ', day);
console.log('Day Weather: ', day['weather'][0]['icon']);
setForcast( forecast => [...forecast, day['weather'][0]['icon']]);
})
});
});
}}>
Search
</Button>
{loading ?
// console.log('forecast: ', forecast)
<WeatherBox
apiKey={apiKey}
name={weatherData['name']}
lat={weatherData['coord']['lat']}
lon={weatherData['coord']['lon']}
feelsLike={weatherData['main']['feels_like']}
highestTemp={weatherData['main']['temp_max']}
lowestTemp={weatherData['main']['temp_min']}
forecast={forecast}
/> : <></>}
);}
For my WeatherBox component
export default function WeatherBox(props) {
let newDate = new Date()
let date = newDate.getDate();
let month = newDate.getMonth() + 1;
let year = newDate.getFullYear();
return (
<Box
className='retrievedInformation'
sx={{
mt: 10,
p: 5,
boxShadow: 'gray 5px 10px 10px 5px',
borderRadius: '20px',
textAlign: 'end',
backgroundImage: `url(${sunny})`,
objectFit: 'contain',
backgroundRepeat: 'no-repeat',
backgroundSize: '500px 500px'
}}>
<Typography
sx={{ fontSize: '50px' }}>
{props.name}
</Typography>
<Typography
sx={{ fontSize: '25px' }}>
Today: {month} / {date} / {year}
</Typography>
<img src={`http://openweathermap.org/img/wn/${props.forecast[0]}#2x.png`} alt='forecast image' />
<Box
display='flex'
flexDirection='row'
sx={{ textAlign: 'end', justifyContent: 'end', alignItems: 'end' }}>
<Typography
sx={{ mr: 3, fontSize: '30px', fontWeight: '300', color: 'gray' }}>
Feels Like:
</Typography>
<Typography
sx={{ fontSize: '30px' }}>
{props.feelsLike} F
</Typography>
</Box>
<Box
display='flex'
flexDirection='row'
justifyContent='end'
alignItems='end'
sx={{ textAlign: 'end' }}>
<Typography
sx={{ mr: 3, fontSize: '20px', fontWeight: '300', color: 'gray', textAlign: 'end' }}>
Highest Temperature:
</Typography>
<Typography
sx={{ fontSize: '20px', textAlign: 'end' }}>
{props.highestTemp} F
</Typography>
</Box>
<Box
display='flex'
flexDirection='row'
justifyContent='end'
alignItems='end'>
<Typography sx={{ mr: 3, fontSize: '20px', fontWeight: '300', color: 'gray', textAlign: 'end' }}>Lowest Temperature: </Typography>
<Typography sx={{ fontSize: '20px', textAlign: 'end' }}> {props.lowestTemp} F</Typography>
</Box>
<Box textAlign='end' alignItems='end' justifyContent='end'>
<Typography sx={{ mt: 5, fontSize: '30px' }}>Weather forecast for the next 7 days</Typography>
<img src={`http://openweathermap.org/img/wn/${props.forecast[1]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[2]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[3]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[4]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[5]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[6]}#2x.png`} alt='forecast image' />
<img src={`http://openweathermap.org/img/wn/${props.forecast[7]}#2x.png`} alt='forecast image' />
</Box>
</Box>
);
}
My forecast array has been update as well and holding all the correct values however, the img tag in weatherbox is still not updating
Thanks for your help in advance
EDIT: Added link to codesandbox
https://codesandbox.io/s/blissful-thunder-u76vwt?file=/src/App.js

Issue
The img tag loads all the images fine for the first call however, the
problem is that when I do another zipcode and clicked search, the
texts updated, but the img tag (the weather images) did not update (
i.e. first search 91001 everything looks great, searched again for
95133, name changed to San Jose but the weather forecast images did
not update from 91001's to 95133's)
You always append forecast data to the forecast state but only reference the first 8 elements.
response["daily"].forEach((day) => {
setForcast((forecast) => [
...forecast, // <-- shallow copy persists old forecast data
day["weather"][0]["icon"]
]);
});
...
<img
src={`http://openweathermap.org/img/wn/${props.forecast[0]}#2x.png`}
alt="forecast image"
/>
...
<img
src={`http://openweathermap.org/img/wn/${props.forecast[1]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[2]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[3]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[4]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[5]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[6]}#2x.png`}
alt="forecast image"
/>
<img
src={`http://openweathermap.org/img/wn/${props.forecast[7]}#2x.png`}
alt="forecast image"
/>
Solution
To resolve, you should overwrite the forecast state when updating.
setForcast(response.daily.map((day) => day.weather[0].icon));
Here's a "optimized" button click handler.
<Button
onClick={async () => {
setLoading(false);
const weather = await currentWeather(zipcode, apiKey);
setWeatherData(weather);
console.log(weather);
const forecast = await sevenDayWeather(
weather.coord.lon,
weather.coord.lat,
apiKey
);
setForcast(forecast.daily.map((day) => day.weather[0].icon));
setLoading(true);
}}
>
Search
</Button>
And for the sake of DRY-ness, mapped forecast images.
{props.forecast.map((id, index) => (
<img
key={index}
src={`http://openweathermap.org/img/wn/${id}#2x.png`}
alt="forecast image"
/>
))}

Related

How can I avoid re-render when props change in a modal in React?

I have a problem. I want to put a form inside a modal in react, and when the user click the button accept submit the data to a given url. But I want the modal be generic enough to wrap many forms but doing this the modal have to receive some parameters and every time the parameters change, the modal re-renders.
I create a custom hooks where I return the form and the data I extract from the form. Then I pass the form as a child of the modal component and the data as prop. Then when the user clic the accept button, the data will submit to the url.
But the form every time I write in it, re-render the modal. I can put the modal code inside every form component and it will work, but it's an ugly solution, the code won't be clean and won't be as efficient as it can. Hope you can help me.
The Modal Code:
`
const ModalDialogForm = (props) => {
const { title = "Modal", isFullScreen = true, open, setOpen, children = "", cleanElements = () => { }, data = "", content } = props;
const Transition = React.forwardRef(function Transition(props, ref) {
return <Slide direction="up" ref={ref} {...props} />;
});
const cleanForm = () => {
document.getElementById("modal-form").reset();
}
return (
<>
<Dialog fullScreen={isFullScreen} open={open} TransitionComponent={Transition} style={{
color: "transparent",
display: "flex", margin: "auto",
justifyContent: "center", flexDirection: "column", borderRadius: "10px"
}}>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar variant='regular'>
<Typography sx={{ ml: 2, flex: 1 }} variant="h6" component="div" style={{ color: "black" }} >
{title}
</Typography>
<IconButton edge="start" color="inherit" onClick={() => setOpen(false)} aria-label="close">
<CancelIcon style={{ color: "black" }} />
</IconButton>
</Toolbar>
</AppBar>
<Paper style={{ backgroundColor: "rgb(249, 249, 249)", height: "100%", borderRadius: "0px" }} elevation={1}>
<form id="modal-form">
{children}
{content ? content() : ""}
</form>
</Paper>
<AppBar sx={{ position: 'relative' }} style={{ backgroundColor: "white" }} elevation={0}>
<Toolbar style={{ display: "flex", justifyContent: "flex-end" }}>
<Button style={{ backgroundColor: "green", color: "white" }} onClick={() => { console.log(data); }}>
Aceptar
</Button>
<Button style={{ color: "black" }} onClick={() => { cleanForm(); cleanElements(); }}>
Limpiar
</Button>
<Button style={{ color: "black" }} onClick={() => setOpen(false)}>
Cerrar
</Button>
</Toolbar>
</AppBar>
</Dialog>
</>
)
}
`
The Page where I call the modal:
`
const renderModal = () => (
<>
<ModalDialogForm isFullScreen={false} title="Adicionar Idioma" open={modalOpened} setOpen={setModalOpened} data={data}>
{getForm()}
</ModalDialogForm>
</>
)
useEffect(() => {
setModal(
modalOpened ? (<>
{renderModal()}
</>
) : (
<></>
)
);
}, [modalOpened, data]);
return (
<div>
<IdiomaTable canInsert={insertar} canModify={modificar} canDelete={eliminar} openModal={() => { setModalOpened(true); }} />
{modal}
</div>
)
`
I solve the problem. It is a temporary solution until I find a better one but works. Just removed the transition property of the Dialog component then the modal re-render but because don't have the transition the UI looks good. It is less fancy, but functional.

Why does liking one option like all the rest?

I am attempting to have a single user be able to choose from 1 of 2 options but when I like one they are all liked for some reason.
This is the result. I have an onClick function on the heart so that it adds the red.
https://i.stack.imgur.com/r73UB.png
Below is the code that runs when I click on the heart. I basically set the usersID into a collection called likes and save thier username
const [likes, setLikes] = useState([])
const [hasLiked, setHasLiked] = useState(false)
const likeFighter = async (e) => {
const docRef = doc(db, 'userpicks', value)
const docSnap = await getDoc(docRef)
const picksRef = doc(db, 'picks', value)
const pickSnap = await getDoc(picksRef)
let fighterID = e.target.id.toLowerCase().replace(' ', '-').replace(' ', '-')
if (hasLiked) {
await deleteDoc(doc(db, 'picks', value, 'likes', userInfo.uid))
}
else {
if (fighterID !== ' ') {
await setDoc(doc(db, 'picks', value, 'likes', userInfo.uid), {
username: userInfo.uid
})
}
}
}
This is what the database looks like. The main collection is called 'picks'. The parent collection that is.
https://i.stack.imgur.com/JVrk3.png
I also have these useEffects with snapshot listeners that run every-time a user likes a particular fighter. How can I have it so that they are only able to like one of the two fighters? If they like the left fighter they cannot like the right and vice versa.
useEffect(() => onSnapshot(collection(db, 'picks', value, 'likes'), (snapshot) =>
setLikes(snapshot.docs)
), [db, value])
useEffect(
() =>
setHasLiked(
likes.findIndex((like) => like.id === userInfo.uid) !== -1
),
[likes]
)
This is the logic that gets the fighter information from the database and renders it on the screen. I tried using the fighters name as an id so that on click it likes that particular fighter but It doesn't work.
const renderFights = fight.map((element, idx) => {
return (
<Paper elevation={0} id={element.fightID} key={idx} sx={{ width: '100%', height: '100%', display: 'flex', justifyContent: 'space-evenly' }} >
<Paper elevation={1} key={element.fighterRed} sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: '50%', m: 3 }}>
<Avatar sx={{ mt: 1 }} src={element.fighterRedImage} />
<Typography variant='body1'> {element.fighterRed} </Typography>
<Typography variant='overline' sx={{ fontSize: '14px' }}> {element.fighterRedRecord} </Typography>
<Paper sx={{ display: 'flex' }} elevation={0} name={element.fightID}>
{hasLiked ?
<FavoriteIcon id={element.fighterRed} onClick={likeFighter} sx={{ cursor: 'pointer', color: 'red' }} /> :
<FavoriteBorder id={element.fighterRed} onClick={likeFighter} sx={{ cursor: 'pointer' }} />
}
{likes.length > 0 && (
<Typography>{likes.length}</Typography>)
}
</Paper>
</Paper>
<Paper elevation={0} sx={{ width: '10%', display: 'flex', flexDirection: 'column', mt: 3, mb: 3, justifyContent: 'space-evenly', alignItems: 'center' }} >
<Typography sx={{ fontSize: '10px', textAlign: 'center' }} variant='overline'> {element.weightClass}</Typography>
<Typography sx={{ fontSize: '10px', textAlign: 'center' }} variant='overline'>vs</Typography>
<Chip label="FINAL U DEC" sx={{ fontSize: '8px' }} />
</Paper>
<Paper elevation={1} key={element.fighterBlue} sx={{ display: 'flex', flexDirection: 'column', alignItems: 'center', width: '50%', m: 3 }}>
<Avatar sx={{ mt: 1 }} src={element.fighterBlueImage} />
<Typography variant='body1'> {element.fighterBlue} </Typography>
<Typography variant='overline' sx={{ fontSize: '14px' }}> {element.fighterBlueRecord} </Typography>
<Paper sx={{ display: 'flex' }} elevation={0}>
{hasLiked ?
<FavoriteIcon id={element.fighterBlue} onClick={likeFighter} sx={{ cursor: 'pointer', color: 'red' }} /> :
<FavoriteBorder id={element.fighterBlue} onClick={likeFighter} sx={{ cursor: 'pointer' }} />
}
{likes.length > 0 && (
<Typography>{likes.length}</Typography>)
}
</Paper>
</Paper>
</Paper>
)
})

How to make certain <div>'s appear/disappear on category selection | ReactJS

I am making a pricing calculator on my site with 3 different options for calculation. I'd like the three categories at the top of the screenshot included to show the respective section (and make the others invisible) and turn that specific button black (it currently turns black on hover but not when clicked) and the others back to grey. Also screenshotted is an example of this working on Airtable's product page.
My script is below; I've been trying to make this work with useState and an onClick function as this is the recommended solution I've found in my research (linked one example of a few similar answers). However, if there is another more suitable approach I appreciate the advice.
import React, { useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import useWindowPosition from '../../hook/useWindowPosition';
import Typography from '#material-ui/core/Typography';
import TextField from '#material-ui/core/TextField';
import Switch from '#material-ui/core/Switch';
const useStyles = makeStyles((theme) => ({
root: {
background: 'white',
paddingTop: '30px',
paddingBottom: '60px',
marginBottom: '-80px',
},
cardRoot: {
width: '90vw',
background: 'white',
marginTop: '20px',
marginBottom: '20px',
},
calculator: {
display: 'flex',
marginLeft: '10vw',
marginTop: '5vh',
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
},
spacing: {
marginTop: '10vh',
marginLeft: '10vw',
},
header: {
fontFamily: 'Nunito',
fontWeight: 'bold',
fontSize: '2rem',
color: '#000',
marginRight: '30px',
},
title: {
fontFamily: 'Nunito',
fontWeight: 'regular',
fontSize: '1.5rem',
color: '#000',
marginRight: '30px',
},
price: {
fontFamily: 'Nunito',
fontWeight: 'regular',
fontSize: '2rem',
color: '#000',
marginRight: '30px',
},
liststyle: {
fontFamily: "Nunito",
fontSize: "1rem",
margin: '10px 10px',
},
list: {
display: "flex",
marginLeft: '8vw',
},
sections: {
textDecoration: 'none',
fontWeight: 'bold',
color: '#B6B6B6',
'&:hover': {
backgroundColor: '#fff',
color: '#000',
},
'&:clicked': {
backgroundColor: '#fff',
color: '#000',
},
},
}));
export default function () {
const classes = useStyles();
const [state, setState] = useState({
ImageNumber: '',
checkedA: false,
LabelImagesPrice: '',
AnimalNumber: '',
AnimalNumberPrice: '',
DatasetImageNumber: '',
DatasetAnimalNumber: '',
DatasetModelPrice: '',
});
const [show, setShow] = useState({
LabelImages: true,
CustomModel: false,
DatasetModel: false,
})
const onClick = () => setShow(true)
const handleSwitchChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
};
const handleChange = (event) => {
console.log(event.target.name);
setState({
...state,
[event.target.name]: event.target.value,
});
};
return (
<section id="pricingcalc" data-scroll-id="pricingcalc" backgroundColor="white">
<div className={classes.root}>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h5"
component="h1"
className={classes.header}
>
Pricing Calculator
</Typography>
</div>
<div>
<ul className={classes.list} style={{ listStyleType: "none" }}>
<li className={classes.liststyle}>
<a className={classes.sections} href="#labelimages" onClick={onClick}>
Label Images
</a>
</li>
<li className={classes.liststyle}>
<a className={classes.sections} href="#custommodel" onClick={onClick}>
Custom Model
</a>
</li>
<li className={classes.liststyle}>
<a className={classes.sections} href="#datasetmodel" onClick={onClick}>
Specialized Model
</a>
</li>
</ul>
</div>
<div className={classes.calculator} name="LabelImages">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Images
</Typography>
<TextField label="" name="ImageNumber" type="text" value={state.ImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Human verified?
</Typography>
<Switch checked={state.checkedA} color="primary" onChange={handleSwitchChange} name="checkedA" />
</div>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="LabelImagesPrice" type="text" value={state.ImageNumber*10 + state.checkedA*99} disabled variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Animals in Model
</Typography>
<TextField label="" name="AnimalNumber" type="text" value={state.AnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="AnimalNumberPrice" disabled type="text" value={state.AnimalNumber*15} disabled variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator} name="DatasetModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Images in Training Dataset
</Typography>
<TextField label="" name="DatasetImageNumber" type="text" value={state.DatasetImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Animals in Model
</Typography>
<TextField label="" name="DatasetAnimalNumber" type="text" value={state.DatasetAnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="DatasetModelPrice" type="text" disabled value={state.DatasetImageNumber*10 + state.DatasetAnimalNumber*2} variant="outlined" onChange={(e) => handleChange(e)} />
</div>
</div>
</section>
);
}
Updated script:
import React, { useState } from 'react';
import { makeStyles } from '#material-ui/core/styles';
import useWindowPosition from '../../hook/useWindowPosition';
import Typography from '#material-ui/core/Typography';
import TextField from '#material-ui/core/TextField';
import Switch from '#material-ui/core/Switch';
const useStyles = makeStyles((theme) => ({
root: {
background: 'white',
paddingTop: '30px',
paddingBottom: '60px',
marginBottom: '-80px',
},
cardRoot: {
width: '90vw',
background: 'white',
marginTop: '20px',
marginBottom: '20px',
},
calculator: {
display: 'flex',
marginLeft: '10vw',
marginTop: '5vh',
[theme.breakpoints.down('md')]: {
flexDirection: 'column',
},
},
spacing: {
marginTop: '10vh',
marginLeft: '10vw',
},
header: {
fontFamily: 'Nunito',
fontWeight: 'bold',
fontSize: '2rem',
color: '#000',
marginRight: '30px',
},
title: {
fontFamily: 'Nunito',
fontWeight: 'regular',
fontSize: '1.5rem',
color: '#000',
marginRight: '30px',
},
price: {
fontFamily: 'Nunito',
fontWeight: 'regular',
fontSize: '2rem',
color: '#000',
marginRight: '30px',
},
liststyle: {
fontFamily: "Nunito",
fontSize: "1rem",
margin: '10px 10px',
},
list: {
display: "flex",
marginLeft: '8vw',
},
sections: {
textDecoration: 'none',
fontWeight: 'bold',
color: '#B6B6B6',
'&:hover': {
backgroundColor: '#fff',
color: '#000',
},
'&:clicked': {
backgroundColor: '#fff',
color: '#000',
},
},
}));
export default function () {
const classes = useStyles();
const checked = useWindowPosition('header');
const [state, setState] = useState({
ImageNumber: '',
checkedA: false,
LabelImagesPrice: '',
AnimalNumber: '',
AnimalNumberPrice: '',
DatasetImageNumber: '',
DatasetAnimalNumber: '',
DatasetModelPrice: '',
});
const [show, setShow] = useState({
LabelImages: true,
CustomModel: false,
DatasetModel: false,
})
const onClick = () => setShow(true)
const handleSwitchChange = (event) => {
setState({ ...state, [event.target.name]: event.target.checked });
};
const handleChange = (event) => {
console.log(event.target.name);
setState({
...state,
[event.target.name]: event.target.value,
});
};
return (
<section id="pricingcalc" data-scroll-id="pricingcalc" backgroundColor="white">
<div className={classes.root}>
<div className={classes.calculator}>
<Typography
gutterBottom
variant="h5"
component="h1"
className={classes.header}
>
Pricing Calculator
</Typography>
</div>
<div>
<ul className={classes.list} style={{ listStyleType: "none" }}>
<li className={classes.liststyle}>
<a
style = {show.labelImages ? {color: 'black'} : {color: 'grey'}}
className={classes.sections}
href="#labelimages"
onClick={onClick}
>
Label Images
</a>
</li>
<li className={classes.liststyle}>
<a
style={show.customModel ? {color: 'black'} : {color: 'grey'}}
className={classes.sections}
href="#customModel"
onClick={onClick}
>
Custom Model
</a>
</li>
<li className={classes.liststyle}>
<a
style={show.datasetModel ? {color: 'black'} : {color: 'grey'}}
className={classes.sections}
href="#datasetModel"
onClick={onClick}
>
Specialized Model
</a>
</li>
</ul>
</div>
{show.labelImages && <div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Images
</Typography>
<TextField label="" name="ImageNumber" type="text" value={state.ImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.labelImages && <div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Human verified?
</Typography>
<Switch checked={state.checkedA} color="primary" onChange={handleSwitchChange} name="checkedA" />
</div>}
{show.labelImages && <div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="LabelImagesPrice" type="text" value={state.ImageNumber*10 + state.checkedA*99} disabled variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.customModel && <div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Animals in Model
</Typography>
<TextField label="" name="AnimalNumber" type="text" value={state.AnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.customModel && <div className={classes.calculator} name="CustomModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="AnimalNumberPrice" disabled type="text" value={state.AnimalNumber*15} disabled variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.datasetModel && <div className={classes.calculator} name="DatasetModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Images in Training Dataset
</Typography>
<TextField label="" name="DatasetImageNumber" type="text" value={state.DatasetImageNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.datasetModel && <div className={classes.calculator} name="DatasetModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.title}
>
Number of Animals in Model
</Typography>
<TextField label="" name="DatasetAnimalNumber" type="text" value={state.DatasetAnimalNumber} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
{show.datasetModel && <div className={classes.calculator} name="DatasetModel">
<Typography
gutterBottom
variant="h6"
component="h1"
className={classes.price}
>
Price
</Typography>
<TextField label="$ (USD)" name="DatasetModelPrice" type="text" disabled value={state.DatasetImageNumber*10 + state.DatasetAnimalNumber*2} variant="outlined" onChange={(e) => handleChange(e)} />
</div>}
</div>
</section>
);
}
For each of the sections you can do something like:
{show.labelImages && <div className={classes.calculator} name="LabelImages"></div>}
and to get the buttons to turn black grey you can use a style tag like:
<a
style = {show.labelImages ? {color: 'black'} : {color: 'grey'}
className={classes.sections}
href="#labelimages"
onClick={onClick}
>
Label Images
</a>

Not able to set initial values of formik form?

I have created a formik form that gets its initial values from the backend database through API calls. Got below error:
Type 'undefined' is not assignable to type 'FormikValues'. TS2322
Not able to resolve the error.
code:
// #ts-ignore
import React, { useState, useEffect } from 'react';
import { Formik, Form, Field } from 'formik';
import {
Typography,
Button,
Grid,
CircularProgress,
Divider,
} from '#material-ui/core';
import * as Yup from 'yup';
import { MyInput } from './comman/MyInput';
import axios from 'axios'
import ThumbUpAltIcon from '#material-ui/icons/ThumbUpAlt';
import Unsubscribed from './Unsubscribed';
const contactSchema = Yup.object().shape({
});
export default function SurveyUnsubscribed(props: any) {
const [isSubmitted, setIsSubmitted] = useState(false);
//const [color, setColor] = useState(true);
const [loading, setLoading] = useState(false);
const [count, setCount] = useState(0);
const [countone, setCountOne] = useState(0);
const [counttwo, setCountTwo] = useState(0);
const [countthree, setCountThree] = useState(0);
const [initialValues, setInitialValues] = useState();
const [state, setState] = useState({
msg: '',
});
let initial:any;
async function getInitialValues() {
try{
const response = await axios.get(`${process.env.REACT_APP_LOCALHOST_DEVELOPMENT_VOTING_API_GET}`)
return response.data;
}catch(error){
console.error(error)
}
}
useEffect(() => {
getInitialValues().then((res:any) => setInitialValues(res));
}, []);
const handleClickCount = () => {
setCount(count + 1);
// setColor(false);
};
const handleClickCountTwo = () => {
setCountTwo(counttwo + 1);
// setColor(false);
}; const handleClickCountThree = () => {
setCountThree(countthree + 1);
// setColor(false);
}; const handleClickCountOne = () => {
setCountOne(countone + 1);
// setColor(false);
};
return (
<React.Fragment>
<Formik
enableReinitialize
initialValues={initialValues}
// count: initial,
// countone: countone,
// counttwo: counttwo,
// countthree: countthree,
// helptext: '',
validationSchema={contactSchema}
onSubmit={(values, { resetForm }) => {
setLoading(true);
console.log(initial)
const data = {
count: values.count,
countone: values.countone,
counttwo: values.counttwo,
countthree: values.countthree,
helptext: values.helptext,
};
console.log(data);
const request = new Request(
`${process.env.REACT_APP_LOCALHOST_DEVELOPMENT_VOTING_API}`,
{
method: 'POST',
headers: new Headers({
'Content-Type': 'application/json',
}),
body: JSON.stringify(data),
},
);
fetch(request)
.then((res) => res.json())
.then((data) => {
if (data.message === 'Thank you for your feedback!') {
setState({
msg: data.message,
});
setIsSubmitted(true);
setTimeout(() => {
setLoading(false);
}, 1500);
} else {
console.log('error');
}
});
setTimeout(() => {
setIsSubmitted(false);
}, 1500);
resetForm();
}}
>
{({ setFieldValue }) => (
<Grid container>
<Grid
item
xs={12}
style={{ paddingLeft: '2em', paddingRight: '2em' }}
>
<Typography
variant="h6"
style={{
marginTop: '1em',
color: '#2F4858',
fontWeight: 'bold',
}}
>
Voting survey </Typography>
<br />
{isSubmitted}
<Form>
<Typography
variant="body1"
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '1em',
}}
>
<Field type="hidden" name="count" component={ThumbUpAltIcon} onClick={handleClickCount} style={{ color: '#C4C4C4', marginRight: '0.4em' }}/>
<Typography
variant="caption"
style={{
position: 'relative',
top: '1.5em',
right: '1.5em',
}}
>
{count}
</Typography>
A </Typography>
<Typography
variant="body1"
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '1em',
}}
>
<Field type="hidden" name="countone" component={ThumbUpAltIcon} onClick={handleClickCountOne} style={{ color: '#C4C4C4', marginRight: '0.4em' }}/>
<Typography
variant="caption"
style={{
position: 'relative',
top: '1.5em',
right: '1.5em',
}}
>
{countone}
</Typography>
B </Typography>
<Typography
variant="body1"
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '1em',
}}
>
<Field type="hidden" name="counttwo" component={ThumbUpAltIcon} onClick={handleClickCountTwo} style={{ color: '#C4C4C4', marginRight: '0.4em' }}/>
<Typography
variant="caption"
style={{
position: 'relative',
top: '1.5em',
right: '1.5em',
}}
>
{counttwo}
</Typography>
C </Typography>
<Typography
variant="body1"
style={{
display: 'flex',
alignItems: 'center',
marginBottom: '1em',
}}
>
<Field type="hidden" name="countthree" component={ThumbUpAltIcon} onClick={handleClickCountThree} style={{ color: '#C4C4C4', marginRight: '0.4em' }}
/>
<Typography
variant="caption"
style={{
position: 'relative',
top: '1.5em',
right: '1.5em',
}}
>
{countthree}
</Typography>
D
</Typography>
<br />
<Typography
variant="h6"
style={{
marginLeft: '2em',
marginTop: '0.5em',
}}
>
What information would help you ?
</Typography>
<Field
id="outlined-multiline-flexible"
type="text"
name="helptext"
component={MyInput}
disabled={isSubmitted}
style={{ marginLeft: '2em' }}
/>
<br />
<br />
<Button
type="submit"
variant="contained"
style={{
background: '#2F4858',
color: 'white',
fontFamily: 'roboto',
fontSize: '1rem',
marginLeft: '2em',
marginBottom: '1em',
}}
>
{loading && (
<CircularProgress
size={25}
color="inherit"
style={{ marginRight: '5px' }}
/>
)}
{loading && <span>submitting</span>}
{!loading && <span>Submit</span>}
</Button>
<br />
{state.msg && (
<Typography
variant="h6"
style={{
color: '#4BB543',
fontFamily: 'roboto-medium',
marginTop: '1em',
}}
>
{' '}
{state.msg}{' '}
</Typography>
)}
</Form>
<Divider
style={{
border: '1px solid #97A1A8',
marginTop: '1em',
marginBottom: '2em',
}}
/>
<Unsubscribed />
</Grid>
</Grid>
)}
</Formik>
</React.Fragment>
);
}
please guys help me with setting formik initial values from the database(Postgresql)
Because you create state initialValues with default value is undefined. So just update default value to an empty object
const [initialValues, setInitialValues] = useState({});

Change the shape of the card when the screen is minimized and when the workspace consists of two words

I have a project in order to organize tasks within companies, and I have a group of workspace that I must display, but when viewing the card changes the shape of the card when the screen is minimized and only when the name of the workspace consists of two words.
As it is clear in the picture, I have a workspace whose name is Heba Youssef, and we notice the change in the shape of the card style when the screen is minimized.
How can I solve this problem?
code.tsx:
interface WorkspaceCardProps {
workspace: Workspace;
}
let theme = createMuiTheme();
theme = responsiveFontSizes(theme);
const WorkspaceCard: FC<WorkspaceCardProps> = (props) => {
const { workspace } = props;
const user = useAuthModule((state) => state.user.user);
console.log('user workspace: ', workspace)
console.log('user' , user.name)
const fileSelectedHandler = event => {
console.log(event)
}
const navigation = useNavigate();
const fileUploadHandler = ()=>{
}
return (
<Box
sx={{
display: 'flex',
flexDirection: 'column',
p: 3
}}
>
<Card
style={{maxWidth: "24rem"}}
sx={{py: '20px'}}>
<Box
sx={{
pl: 3,
pr:3,
pb:3,
pt:2
}}
>
<Box
sx={{
alignItems: 'center',
display: 'flex',
}}
>
<Avatar
onClick={fileUploadHandler}
onChange={fileSelectedHandler}
style={{height: "5.6rem", width: "5.6rem"}}
alt="Author"
src="https://t4.ftcdnA25Jjm2q.jpg"
// src={workspace.author.avatar}
>
</Avatar>
<Box sx={{ml: 2}}>
<Link
color="textPrimary"
component={RouterLink}
to="#"
variant="h6"
style={{textAlign: "center", fontSize: "1.9rem",
paddingLeft: "0.8rem"}}
>
{workspace.name}
{/*Slark*/}
</Link>
<Typography
color="textSecondary"
variant="body2"
style={{textAlign: "center", paddingLeft: "0.8rem"}}
>
by
{' '}
<Link
color="textPrimary"
component={RouterLink}
to="#"
variant="subtitle2"
>
{user.name}
</Link>
</Typography>
</Box>
</Box>
</Box>
<Divider />
<Box
sx={{
alignItems: 'center',
display: 'flex',
pl: 2,
pr: 3,
pt:2
}}
>
<Box
sx={{
alignItems: 'center',
display: 'flex',
ml: 2
}}
>
<UsersIcon fontSize="small"/>
<Typography
color="textSecondary"
sx={{ml: 1}}
variant="subtitle2"
>
{/*{workspace.membersCount}*/}
4
</Typography>
</Box>
<Box sx={{
ml: 2
}}
>
<Button>
<a href={`/workspace-settings/settings/${workspace._id}`} >
<ViewComfyRoundedIcon style={{fontSize: 30}}/>
</a>
</Button>
</Box>
</Box>
</Card>
</Box>
);
};
WorkspaceCard.propTypes = {
// #ts-ignore
workspace: PropTypes.object.isRequired
};
export default WorkspaceCard;
I believe you are using the Grid component. You should specify a higher value for either xs, sm, md, ... You have to guess how long a workspace name typically is and set the value(s) accordingly.
The other way to you may consider is to add noWrap the following:
<Link
color="textPrimary"
component={RouterLink}
to="#"
variant="h6"
style={{
textAlign: "center", fontSize: "1.9rem",
paddingLeft: "0.8rem"
}}
noWrap
>
{workspace.name}
</Link>
Although I'm not sure whether it is a good UI design, given you have left little space to display text that is potentially very long.

Resources