saleor-dashboard/src/components/ConfirmButton/ConfirmButton.tsx

185 lines
5 KiB
TypeScript
Raw Normal View History

2019-06-19 14:40:52 +00:00
import Button, { ButtonProps } from "@material-ui/core/Button";
import CircularProgress from "@material-ui/core/CircularProgress";
import {
createStyles,
Theme,
2019-10-30 14:34:24 +00:00
WithStyles,
withStyles
2019-06-19 14:40:52 +00:00
} from "@material-ui/core/styles";
import CheckIcon from "@material-ui/icons/Check";
import { buttonMessages } from "@saleor/intl";
2019-06-19 14:40:52 +00:00
import classNames from "classnames";
2019-08-09 10:26:22 +00:00
import React from "react";
import { FormattedMessage } from "react-intl";
2019-06-19 14:40:52 +00:00
export type ConfirmButtonTransitionState =
| "loading"
| "success"
| "error"
| "default";
2019-10-30 14:34:24 +00:00
const styles = (theme: Theme) =>
2019-06-19 14:40:52 +00:00
createStyles({
error: {
"&:hover": {
backgroundColor: theme.palette.error.main
},
backgroundColor: theme.palette.error.main,
color: theme.palette.error.contrastText
},
icon: {
marginLeft: "0 !important",
position: "absolute",
transitionDuration: theme.transitions.duration.standard + "ms"
},
invisible: {
opacity: 0
},
label: {
alignItems: "center",
display: "flex",
transitionDuration: theme.transitions.duration.standard + "ms"
},
progress: {
"& svg": {
color: theme.palette.common.white,
margin: 0
},
position: "absolute",
transitionDuration: theme.transitions.duration.standard + "ms"
},
success: {
"&:hover": {
backgroundColor: theme.palette.primary.main
},
backgroundColor: theme.palette.primary.main,
color: theme.palette.primary.contrastText
}
});
export interface ConfirmButtonProps
extends Omit<ButtonProps, "classes">,
WithStyles<typeof styles> {
transitionState: ConfirmButtonTransitionState;
}
interface ConfirmButtonState {
displayCompletedActionState: boolean;
}
2019-12-03 15:28:40 +00:00
const ConfirmButton = withStyles(styles, { name: "ConfirmButton" })(
2019-06-19 14:40:52 +00:00
class ConfirmButtonComponent extends React.Component<
ConfirmButtonProps &
WithStyles<
"error" | "icon" | "invisible" | "label" | "progress" | "success"
>,
ConfirmButtonState
> {
2019-12-02 10:49:14 +00:00
state: ConfirmButtonState = {
displayCompletedActionState: false
};
timeout = null;
2019-06-19 14:40:52 +00:00
static getDerivedStateFromProps(
nextProps: ConfirmButtonProps,
prevState: ConfirmButtonState
): ConfirmButtonState {
if (nextProps.transitionState === "loading") {
return {
displayCompletedActionState: true
};
}
return prevState;
}
componentDidUpdate(prevProps: ConfirmButtonProps) {
const { transitionState } = this.props;
if (prevProps.transitionState !== transitionState) {
if (
(["error", "success"] as ConfirmButtonTransitionState[]).includes(
transitionState
)
) {
this.timeout = setTimeout(
() =>
this.setState({
displayCompletedActionState: false
}),
2000
);
} else if (transitionState === "loading") {
clearTimeout(this.timeout);
}
}
}
componentWillUnmount() {
clearTimeout(this.timeout);
}
render() {
const {
children,
classes,
className,
disabled,
transitionState,
onClick,
...props
} = this.props;
const { displayCompletedActionState } = this.state;
return (
<Button
variant="contained"
onClick={transitionState === "loading" ? undefined : onClick}
color="primary"
className={classNames({
[classes.error]:
transitionState === "error" && displayCompletedActionState,
[classes.success]:
transitionState === "success" && displayCompletedActionState,
[className]: true
})}
disabled={!displayCompletedActionState && disabled}
{...props}
>
<CircularProgress
size={24}
color="inherit"
className={classNames({
[classes.progress]: true,
[classes.invisible]: transitionState !== "loading"
})}
/>
<CheckIcon
className={classNames({
[classes.icon]: true,
[classes.invisible]: !(
transitionState === "success" && displayCompletedActionState
)
})}
/>
<span
className={classNames({
[classes.label]: true,
[classes.invisible]:
(transitionState === "loading" ||
transitionState === "success") &&
displayCompletedActionState
})}
>
{transitionState === "error" && displayCompletedActionState ? (
<FormattedMessage defaultMessage="Error" description="button" />
) : (
children || <FormattedMessage {...buttonMessages.confirm} />
)}
2019-06-19 14:40:52 +00:00
</span>
</Button>
);
}
}
);
ConfirmButton.displayName = "ConfirmButton";
export default ConfirmButton;