How to set the "save" button to summit and not "new" - reactjs

Sorry, this is my first post and I'm new to React.
I have this code below and I use steps for the buttons, however I would like the save button to be the submit type and only it, thanks for your help now.
<React.Fragment>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Saved
</Typography>
</React.Fragment>
) : (
<React.Fragment>
<Box sx={{ display: 'flex', justifyContent: 'flex-end', mb: 4}}>
{activeStep !== 0 && (
<Button onClick={handleBack} sx={{ mt: 3, ml: 1 }}>
Back
</Button>
)}
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 3, ml: 1 }}
>
{activeStep === steps.length - 1 ? 'Save' : 'New'}
</Button>
</Box>
{getStepContent(activeStep)}
</React.Fragment>
)}
</React.Fragment>
</React.Fragment>
and these are the steps functions
function CheckoutContent() {
const [activeStep, setActiveStep] = React.useState(0);
const handleNext = () => {
setActiveStep(activeStep + 1);
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
i'm using material-ui for this.

If I understand your question, this is what you can do:
const savable = activeStep === steps.length;
<Button
type={savable ? "submit" : undefined}
variant="contained"
onClick={savable ? undefined : handleNext}
sx={{ mt: 3, ml: 1 }}
>
{savable ? "Save" : "New"}
</Button>

You can do a conditional rendering:
Check the updated codesandbox
{activeStep === STEPS.length - 1 ? (
<Button variant="contained"
type="submit"
sx={{ mt: 3, ml: 1 }}
> Save </Button>
) : (
<Button variant="contained"
onClick={handleNext}
sx={{ mt: 3, ml: 1 }}
> New </Button>
)}

Related

How to swap MUI icon on IconButton when hovering

I have these tabs that have a close button on them, if the content in them has edits then the close icon turns to a circle, similar to visual code.
{tabs.map((tab, index) => {
const child = (
<StyledTab
label={
<span>
{tab.label + ':' + tab.hasEdit}
<IconButton size="small" component="span" onClick={() => closeClickHandler(tab.value)}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
key={index}
/>
);
return (
<DraggableTab
label={
<span>
{tab.label}
<IconButton size="small" component="span" onClick={() => {
closeClickHandler(tab.value);
}}>
{tab.hasEdit ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
</span>
}
value={tab.value}
index={index}
key={index}
child={child}
/>
);
})}
What I'm having trouble with is getting the icon to change from a circle to a close icon while hovering over the button.
Could someone give me a hand on a good way to implement this please?!
You could do this by adding a state for the items. Then add a onMouseEnter and onMouseLeave events on the IconButton. When hovering we can add the index to the array and finally remove when we're leaving. To determine if a icon needs to change we can check if the index in in the hoveringItems.
const [hoveringItems, setHoveringItems] = useState([]);
function handleHover(index, isLeaving) {
setHoveringItems((prevItems) => {
if (isLeaving) return prevItems.filter((item) => item !== index);
return [...prevItems, index];
});
}
return (
<IconButton
size="small"
component="span"
onClick={() => {
closeClickHandler(tab.value);
}}
onMouseEnter={() => handleHover(index, false)}
onMouseLeave={() => handleHover(index, true)}
>
{tab.hasEdit || hoveringItems.includes(index) ? (
<CircleIcon style={{ fontSize: "12px" }} />
) : (
<CloseIcon style={{ fontSize: "18px" }} />
)}
</IconButton>
);

How can I change the button color

Here in this one I have already declared the onClick but now I want to change the color of button whenever I click it should
<Button
className={classes.button_reset}
onClick={() => setShowResetPass((current) => !current)}
>
Reset Password
</Button>
<Button
sx={{ ml: "20px" }}
onClick={handleCancel}
className={classes.button_light}
>
Cancel
</Button>
<Grid md={6} xs={12}>
{showResetPass && (
<>
<Typography
color="#05445E"
fontFamily="'Jost', sans-serif"
fontSize={15}
sx={{ mt: "20px" }}
>
Enter New Password
</Typography>
<Input
className={classes.inputEmail}
fullWidth
type="password"
/>
</>
)}
This is the states I have used
const [showResetPass, setShowResetPass] = useState(false);
You could do something like that:
<Button
sx={{ ml: "20px" }}
onClick={handleCancel}
className={showResetPass ? classes.button_light : classes.button_dark }
>

Overriding MUI Stepper

I need to change a Mui Stepper ( which the code works perfetly )
but what I need is a bit different ,
Instead of having this :
I want to get the text under the icon and instead of having a line between tow steps I prefer to have a '<'
Here is the code :
import Box from '#mui/material/Box';
import Stepper from '#mui/material/Stepper';
import Step from '#mui/material/Step';
import StepButton from '#mui/material/StepButton';
import Button from '#mui/material/Button';
import Typography from '#mui/material/Typography';
const steps = ['Select campaign settings', 'Create an ad group', 'Create an ad'];
export default function HorizontalNonLinearStepper() {
const [activeStep, setActiveStep] = React.useState(0);
const [completed, setCompleted] = React.useState<{
[k: number]: boolean;
}>({});
const totalSteps = () => {
return steps.length;
};
const completedSteps = () => {
return Object.keys(completed).length;
};
const isLastStep = () => {
return activeStep === totalSteps() - 1;
};
const allStepsCompleted = () => {
return completedSteps() === totalSteps();
};
const handleNext = () => {
const newActiveStep =
isLastStep() && !allStepsCompleted()
? // It's the last step, but not all steps have been completed,
// find the first step that has been completed
steps.findIndex((step, i) => !(i in completed))
: activeStep + 1;
setActiveStep(newActiveStep);
};
const handleBack = () => {
setActiveStep((prevActiveStep) => prevActiveStep - 1);
};
const handleStep = (step: number) => () => {
setActiveStep(step);
};
const handleComplete = () => {
const newCompleted = completed;
newCompleted[activeStep] = true;
setCompleted(newCompleted);
handleNext();
};
const handleReset = () => {
setActiveStep(0);
setCompleted({});
};
return (
<Box sx={{ width: '100%' }}>
<Stepper nonLinear activeStep={activeStep}>
{steps.map((label, index) => (
<Step key={label} completed={completed[index]}>
<StepButton color="inherit" onClick={handleStep(index)}>
{label}
</StepButton>
</Step>
))}
</Stepper>
<div>
{allStepsCompleted() ? (
<React.Fragment>
<Typography sx={{ mt: 2, mb: 1 }}>
All steps completed - you&apos;re finished
</Typography>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
<Box sx={{ flex: '1 1 auto' }} />
<Button onClick={handleReset}>Reset</Button>
</Box>
</React.Fragment>
) : (
<React.Fragment>
<Typography sx={{ mt: 2, mb: 1 }}>Step {activeStep + 1}</Typography>
<Box sx={{ display: 'flex', flexDirection: 'row', pt: 2 }}>
<Button
color="inherit"
disabled={activeStep === 0}
onClick={handleBack}
sx={{ mr: 1 }}
>
Back
</Button>
<Box sx={{ flex: '1 1 auto' }} />
<Button onClick={handleNext} sx={{ mr: 1 }}>
Next
</Button>
{activeStep !== steps.length &&
(completed[activeStep] ? (
<Typography variant="caption" sx={{ display: 'inline-block' }}>
Step {activeStep + 1} already completed
</Typography>
) : (
<Button onClick={handleComplete}>
{completedSteps() === totalSteps() - 1
? 'Finish'
: 'Complete Step'}
</Button>
))}
</Box>
</React.Fragment>
)}
</div>
</Box>
);
}
Is there a way to override the MUI Stepper styles ?
Thank you in advance
Okay so basically it was 2 steps. The first one was to make the labels appear below the icons which was relatively easy.
I had to add alternativeLabel as a prop to the <Stepper />.
The next step was to remove the lines and replace them with < which wasn't straightforward. I did that by styling the .MuiStepConnector class, replacing its content and removing the border.
<Stepper
nonLinear
alternativeLabel
activeStep={activeStep}
sx={{
".MuiStepConnector-root": {
top: 0
},
".MuiStepConnector-root span": {
borderColor: "transparent"
},
".MuiStepConnector-root span::before": {
display: "flex",
justifyContent: "center",
content: '"<"'
}
}}
>
This is the result:

How to submit and validate a form from outside component ReactJS

I have a multi-step component on which I would like to have a form in one of the steps, so when the user tries to go to the next step I could validate the input and submit the form. So far I have this code, but I haven't figured how to validate and submit the code from the outside button.
I would appreciate your help.
import CostumForm from './NannySignupComponents/InformacionPersonal';
const steps = ['Shipping address', 'Payment details', 'Review your order'];
const theme = createTheme();
export default function Checkout() {
function getStepContent(step) {
switch (step) {
case 0:
return (
<CostumForm/>
);
case 1:
return ;
case 2:
return ;
default:
throw new Error('Unknown step');
}
}
const [activeStep, setActiveStep] = useState(0);
const handleNext = () => {
setActiveStep(activeStep + 1);
this.setState({submitFromOutside: true})
};
const handleBack = () => {
setActiveStep(activeStep - 1);
};
return (
<ThemeProvider theme={theme}>
<CssBaseline />
<AppBar
position="absolute"
color="default"
elevation={0}
sx={{
position: 'relative',
borderBottom: (t) => `1px solid ${t.palette.divider}`,
}}
>
<Toolbar>
<Typography variant="h6" color="inherit" noWrap>
Company name
</Typography>
</Toolbar>
</AppBar>
<Container component="main" maxWidth="sm" sx={{ mb: 4 }} >
<Paper variant="outlined" sx={{ my: { xs: 3, md: 6 }, p: { xs: 2, md: 3 } }}>
<Typography component="h1" variant="h4" align="center">
Checkout
</Typography>
<Stepper activeStep={activeStep} sx={{ pt: 3, pb: 5 }}>
{steps.map((label) => (
<Step key={label}>
<StepLabel>{label}</StepLabel>
</Step>
))}
</Stepper>
<React.Fragment>
{activeStep === steps.length ? (
<React.Fragment>
<Typography variant="h5" gutterBottom>
Thank you for your order.
</Typography>
<Typography variant="subtitle1">
Your order number is #2001539. We have emailed your order
confirmation, and will send you an update when your order has
shipped.
</Typography>
</React.Fragment>
) : (
<React.Fragment>
{getStepContent(activeStep)}
<Box sx={{ display: 'flex', justifyContent: 'flex-end' }}>
{activeStep !== 0 && (
<Button onClick={handleBack} sx={{ mt: 3, ml: 1 }} >
Back
</Button>
)}
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 3, ml: 1 }}
>
{activeStep === steps.length - 1 ? 'Place order' : 'Next'}
</Button>
</Box>
</React.Fragment>
)}
</React.Fragment>
</Paper>
</Container>
</ThemeProvider>
);
}

how to increase the size of the stepper in MUI

I want to increase the size of the stepper . also want to add a horizontal line before the initial step content. how it would be possible here I am attaching my code . I have done adding width and height properties. but Its not worked. just stuck with this. how the customization is possible on this stepper component. need help. I am new to react.js and MUI.
<Stepper activeStep={activeStep} orientation="vertical">
{steps.map((step, index) => (
<Step key={step.label}>
<StepLabel
optional={
index === 2 ? (
<Typography variant="caption">Last step</Typography>
) : null
}
>
{step.label}
</StepLabel>
<StepContent>
<Box sx={{ mb: 2 }}>
<div>
<Button
variant="contained"
onClick={handleNext}
sx={{ mt: 1, mr: 1 }}
>
{index === steps.length - 1 ? 'Finish' : 'Continue'}
</Button>
<Button
disabled={index === 0}
onClick={handleBack}
sx={{ mt: 1, mr: 1 }}
>
Back
</Button>
</div>
</Box>
</StepContent>
</Step>
))}
</Stepper>
{activeStep === steps.length && (
<Paper square elevation={0} sx={{ p: 3 }}>
<Typography>All steps completed - you&apos;re finished</Typography>
<Button onClick={handleReset} sx={{ mt: 1, mr: 1 }}>
Reset
</Button>
</Paper>
)}
</Box> ```
Perhaps you could add a custom css to your webpage :
.MuiStepLabel-labelContainer span {
font-size: xx-large;
}
You can adjust to your desired font size by changing the "font-size" value.
You can use a Theme.
Like so:
import { createTheme } from "#mui/material";
const theme = createTheme({typography: {fontSize: 20}});
function App(){
...
return (
<>
<ThemeProvider theme={theme}>
<Stepper ...
</Stepper>
</ThemeProvider>
...
</>
}
The lines in between are a bit of. I could not find a way to prevent this.

Resources