I have different places that use the same input component.
Below are the input component:
const stationSelection = (stationName) => {
return (
<Paper
component="form"
elevation={5}
sx={{
m: '10px 0 30px 5px',
p: '2px 4px',
display: 'flex',
alignItems: 'center',
width: 300,
}}
>
//HERE
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="Please select a station."
value={stationName}
onChange={ /*how to get the data each of the input*/ }
/>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton
color="primary"
sx={{ p: '10px' }}
aria-label="directions"
>
<ArrowDropDownCircleOutlinedIcon />
</IconButton>
</Paper>
)
}
In my react app, I will use it two times for different input.
<CardContent className="default-font">
<Box sx={{ mb: 10 }}>
<Box className="bold">DEPARTURE STATION</Box>
{stationSelection(departStation)} //HERE
<Box className="center">
<Box className="bold" sx={{ flexGrow: 1 }}>
ARRIVAL STATION
</Box>
<IconButton
color="primary"
sx={{ p: '5px', m: '-10px 0 -10px 0' }}
>
<ImportExportIcon />
</IconButton>
</Box>
{stationSelection(arriveStation)} //HERE
</Box>
{ticketDetails()}
</CardContent>
Because I use it two times by using the different variables into the same component, it makes it difficult for me to found out a way to get the data out from the component.
Here are my useState in case you need that.
const [departStation, setDepartStation] = useState('');
const [arriveStation, setArriveStation] = useState('');
Basically, I need to get that two user input.
Full code link.
First, you functional component should start with a capital letter, so change your declaration to:
const StationSelection = ...
Second, in order to edit the state in your component, you should also pass the setter method, and change it in the onChange function:
const StationSelection = ({ stationName, setStationName }) => {
const handleStationChange = (e) => {
setStationName(e.target.value)
}
return (
<Paper
component="form"
elevation={5}
sx={{
m: '10px 0 30px 5px',
p: '2px 4px',
display: 'flex',
alignItems: 'center',
width: 300,
}}
>
//HERE
<InputBase
sx={{ ml: 1, flex: 1 }}
placeholder="Please select a station."
value={stationName}
onChange={handleStationChange}
/>
<Divider sx={{ height: 28, m: 0.5 }} orientation="vertical" />
<IconButton
color="primary"
sx={{ p: '10px' }}
aria-label="directions"
>
<ArrowDropDownCircleOutlinedIcon />
</IconButton>
</Paper>
)
}
Finally, change your main component like this
<CardContent className="default-font">
<Box sx={{ mb: 10 }}>
<Box className="bold">DEPARTURE STATION</Box>
<StationSelection stationName={departStation} setStationName={setDepartStation} />
<Box className="center">
<Box className="bold" sx={{ flexGrow: 1 }}>
ARRIVAL STATION
</Box>
<IconButton
color="primary"
sx={{ p: '5px', m: '-10px 0 -10px 0' }}
>
<ImportExportIcon />
</IconButton>
</Box>
<StationSelection stationName={arriveStation} setStationName={setArriveStation} />
</Box>
{ticketDetails()}
</CardContent>
Related
I am pretty new to React. I was actually building an AppBar with a logo at center based on a suggestion in this post
<Box sx={{ display: "flex", alignItems: "center", flex: "1" }}>
<IconButton
color="inherit"
aria-label="open drawer"
onClick={onDrawerOpen}
edge="start"
sx={{ mr: 2, ...(open && { display: "none" }) }}
>
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
TITLE
</Typography>
</Box>
But is there is any best way of specifying a single class or constant for these settings outside the definition like this
<IconButton class='settings'>
instead of all this
Tried the way #Dimitriy suggested and below my code
export default function AppBar({ open, onDrawerOpen }:any) {
const theme = useTheme();
const iconButtonOptions = {
color: "inherit",
ariaLabel: "open drawer",
onClick: onDrawerOpen,
edge: "start",
sx: {{ mr: 2, ...(open && { display: "none" }) }}
}
return (
<AppBar position="fixed" style={{ background: "#002a5e" }} open={open}>
<Toolbar>
<Box sx={{ display: "flex",flexDirection:"row", alignItems: "center", flex: "1" }}>
<IconButton {...iconButtonOptions} >
<MenuIcon />
</IconButton>
<Typography variant="h6" noWrap component="div">
TITLE
</Typography>
</Box>
<Box
component="img"
sx={{
height: 32,
}}
alt="MyLogo"
src={logo}
/>
<Box sx={{ flex: "1" }}></Box>
</Toolbar>
</AppBar>
);
}
But its saying
Cannot redeclare block-scoped variable '(Missing)'.ts(2451)
Yes, there's actually is the way for that.
First, you can make a new object variable that will hold all of your props.
Example:
const iconBtnProps = {
color: 'inherit',
aria-label: 'open drawer',
onClick: onDrawerOpen,
edge: 'start',
sx: { mr: 2, ...(open && { display: "none" }) }
};
// render the <IconButton /> component and spread the object
<IconButton {...iconBtnProps} />
I would advise you to check styled-components. It would really make things easier for styling components.
You can't define jsx component props through classes. But if you want to make your jsx more understandable, or avoid repetition, you can move all the props into an object.
const iconButtonOptions = {
color: "inherit",
ariaLabel: "open drawer",
onClick: onDrawerOpen,
edge: "start",
sx: { mr: 2, ...(open && { display: "none" }) }
}
return (
<IconButton {...iconButtonOptions}>
<MenuIcon />
</IconButton>
)
I want to implement flex system from material-ui using the Stack component Im faced with a issue. The other half of my screen is displaying another component or blank space and I dont know how to get rid of it.
I'm using the Stack component from material-ui and the normal html iframe tag to build a code editor. Any Idea how I can fix this using Stack?
Screenshot of UI:
Here is my code:
index.js
<Stack sx={{ bgcolor: 'white', pt: 1 }}>
<TabContext value={value} >
<Box sx={{ borderBottom: 1, borderColor: 'divider', bgcolor: 'white' }}>
<TabList onChange={handleChange} >
<Tab label="HTML" value="1" />
<Tab label="CSS" value="2" />
<Tab label="JS" value="3" />
<Tab label="Output" value="4" sx={{ display: { xs: 'block', md: 'none' }, mt: 1 }} />
</TabList>
</Box>
{value === '4' ?
<Stack sx={{ height: 'calc(100vh - 201px)' }}>
<iframe title="result"
sandbox="allow-scripts"
frameBorder="0"
width="100%"
srcDoc={iframeDisplay}
/>
</Stack>
:
<Stack direction="row" sx={{ width: '100%', height: '100%', position: 'relative'}}>
<Stack sx={{ width: { xs: '100%', md: '50%' }, bgcolor: "white" }}>
<TabPanel value={value} sx={{ p: 0 }}>
<CodeMirror
value={codeEditor.value}
height={CODE_EDITOR_PROPS.height}
theme={CODE_EDITOR_PROPS.theme}
extensions={codeEditor.extensions}
onChange={onChange}
/>
</TabPanel>
</Stack>
<Box sx={{ display: { xs: 'none', md:'flex' }, height: 'calc(100vh - 201px)', width: 'calc(50% - 1024px)'}}>
<iframe
title="result"
frameBorder="0"
height="calc(100vh - 201px)"
srcDoc={iframeDisplay}
/>
</Box>
</Stack>}
</TabContext>
</Stack>
In my table each row has a list of attachments that I need to display in detailPanel.
This is my code of details panel
detailPanel={(rowData) => {
return rowData?.document_attachment ? rowData?.document_attachment.map((attachment) => {
return <Box
sx={{ m: 1 }}
onClick={() => handleClickPreviewDoc(attachment)}
>
<Typography sx={{ fontSize: "13px", display: "Flex", alignItems: "center", gap: "10px" }}
>
<FilePresentIcon sx={{ fontSize: "13px", opacity: "0.6" }} />
{attachment.name}
</Typography>
</Box>
}):<Box
sx={{ m: 1 }}
>
<Typography sx={{ fontSize: "13px", display: "Flex", alignItems: "center", gap: "10px" }}
>
No Attachment Found
</Typography>
</Box>
}}
This does not display any attachment even though it is inside the data.
Okay this is for someone who also had this problem, in order to access the list inside the rowData you have to write rowData.rowData.
so correct code is:
detailPanel={(rowData) => {
return rowData?.rowData?.document_attachment ? rowData?.rowData?.document_attachment.map((attachment) => {
return <Box
sx={{ m: 1 }}
onClick={() => handleClickPreviewDoc(attachment)}
>
<Typography sx={{ fontSize: "13px", display: "Flex", alignItems: "center", gap: "10px" }}
>
<FilePresentIcon sx={{ fontSize: "13px", opacity: "0.6" }} />
{attachment.name}
</Typography>
</Box>
}):<Box
sx={{ m: 1 }}
>
<Typography sx={{ fontSize: "13px", display: "Flex", alignItems: "center", gap: "10px" }}
>
No Attachment Found
</Typography>
</Box>
}}
This problem might only be in material-table/core.
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>
)
})
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.