update MessageManager

This commit is contained in:
AlicjaSzu 2020-06-23 13:47:30 +02:00
parent f4d570c7e5
commit b3eb13a785
8 changed files with 279 additions and 90 deletions

View file

@ -0,0 +1,5 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<rect x="10.2726" y="9.00024" width="17.9987" height="1.79987" transform="rotate(45 10.2726 9.00024)" fill="#FE6D76"/>
<rect x="23" y="10.2727" width="17.9987" height="1.79987" transform="rotate(135 23 10.2727)" fill="#FE6D76"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View file

@ -0,0 +1,3 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 32C24.8366 32 32 24.8366 32 16C32 7.16344 24.8366 0 16 0C7.16344 0 0 7.16344 0 16C0 24.8366 7.16344 32 16 32ZM15 20V8H17V20H15ZM15 24V22H17V24H15Z" fill="#CAD8DF"/>
</svg>

After

Width:  |  Height:  |  Size: 321 B

View file

@ -0,0 +1,4 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M23.9167 10.306L12.5417 23L7 16.0699L8.48477 14.8326L12.611 20.0641L22.4919 9L23.9167 10.306Z" fill="#60DAA0"/>
</svg>

After

Width:  |  Height:  |  Size: 312 B

View file

@ -0,0 +1,5 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="16" cy="16" r="16" fill="#F5FAFB"/>
<rect x="10.2726" y="9.00024" width="17.9987" height="1.79987" transform="rotate(45 10.2726 9.00024)" fill="#D98E1D"/>
<rect x="23" y="10.2727" width="17.9987" height="1.79987" transform="rotate(135 23 10.2727)" fill="#D98E1D"/>
</svg>

After

Width:  |  Height:  |  Size: 380 B

View file

@ -3,115 +3,170 @@ import IconButton from "@material-ui/core/IconButton";
import Snackbar from "@material-ui/core/Snackbar"; import Snackbar from "@material-ui/core/Snackbar";
import Typography from "@material-ui/core/Typography"; import Typography from "@material-ui/core/Typography";
import CloseIcon from "@material-ui/icons/Close"; import CloseIcon from "@material-ui/icons/Close";
import React from "react"; import classNames from "classnames";
import React, { useState } from "react";
import { FormattedMessage } from "react-intl";
import { IMessage, MessageContext } from "./"; import { IMessage, MessageContext } from "./";
import { useStyles } from "./styles";
interface Message extends IMessage { interface Message extends IMessage {
key: string; key: string;
} }
interface MessageManagerState {
message: Message;
opened: boolean;
}
export class MessageManager extends React.Component<{}, MessageManagerState> { export const MessageManager = props => {
state: MessageManagerState = { const { children } = props;
message: { key: "0", onUndo: undefined, text: "" },
opened: false
};
queue = [];
handleClose = (_, reason) => { const [message, setMessage] = useState<Message>({
key: "0",
onUndo: undefined,
status: "info",
text: ""
});
const [opened, setOpened] = useState(false);
const classes = useStyles({});
const {
action,
autohide = 3000,
title,
text,
key,
onUndo,
status = "info"
} = message;
const queue = [];
const handleClose = (_, reason) => {
if (reason === "clickaway") { if (reason === "clickaway") {
return; return;
} }
this.setState({ opened: false }); setOpened(false);
}; };
handleExited = () => { const processQueue = () => {
this.processQueue(); if (queue.length > 0) {
setMessage(queue.shift());
setOpened(true);
}
}; };
pushMessage = (message: IMessage) => { const handleExited = () => {
this.queue.push({ processQueue();
};
const pushMessage = (message: IMessage) => {
queue.push({
key: new Date().getTime(), key: new Date().getTime(),
...message ...message
}); });
if (this.state.opened) { if (opened) {
this.setState({ opened: false }); setOpened(false);
} else { } else {
this.processQueue(); processQueue();
} }
}; };
processQueue = () => { return (
if (this.queue.length > 0) { <>
this.setState({ <Snackbar
message: this.queue.shift(), key={key}
opened: true anchorOrigin={{
}); horizontal: "right",
} vertical: "top"
}; }}
open={opened}
render() { autoHideDuration={autohide}
const { autohide = 3000, title, text, key, onUndo } = this.state.message; onClose={handleClose}
return ( onExited={handleExited}
<> ContentProps={{
<Snackbar "aria-describedby": "message-id"
key={key} }}
anchorOrigin={{ className={classNames(classes.snackbar, {
horizontal: "right", [classes.error]: status === "error",
vertical: "top" [classes.success]: status === "success",
}} [classes.warning]: status === "warning"
open={this.state.opened} })}
autoHideDuration={autohide} message={
onClose={this.handleClose} <span id="message-id" data-tc="notification">
onExited={this.handleExited} {title && (
ContentProps={{ <Typography variant="h5" style={{ fontWeight: "bold" }}>
"aria-describedby": "message-id" {title}
}} </Typography>
message={ )}
<span id="message-id" data-test="notification"> <Typography
{title && ( className={status === "info" ? classes.textInfo : classes.text}
<Typography variant="h5" style={{ marginBottom: "1rem" }}>
{title}
</Typography>
)}
{text}
</span>
}
title={title}
action={[
!!onUndo ? (
<Button
key="undo"
color="secondary"
size="small"
onClick={this.handleClose as any}
data-test="button-undo"
>
UNDO
</Button>
) : (
undefined
),
<IconButton
key="close"
aria-label="Close"
color="inherit"
onClick={this.handleClose as any}
> >
<CloseIcon /> {text}
</IconButton> </Typography>
]} </span>
/> }
<MessageContext.Provider value={this.pushMessage}> title={title}
{this.props.children} action={[
</MessageContext.Provider> !!onUndo ? (
</> <Button
); key="undo"
} color="default"
} size="small"
onClick={handleClose as any}
data-tc="button-undo"
>
<FormattedMessage
defaultMessage="Undo"
description="snackbar button undo"
/>
</Button>
) : (
undefined
),
!!action ? (
<Button
key="action"
color="default"
size="small"
onClick={() => {
action();
handleClose(null, null);
}}
data-tc="button-action"
>
<FormattedMessage
defaultMessage="Action"
description="snackbar button action"
/>
</Button>
) : (
undefined
),
<IconButton
key="close"
aria-label="Close"
color="inherit"
onClick={handleClose as any}
className={classes.closeBtn}
>
<CloseIcon />
</IconButton>,
<div className={classes.progressBarContainer} key="progressBar">
<div
className={classNames(classes.progressBar, {
[classes.progressBarActive]: opened,
[classes.progressBarSuccess]: status === "success",
[classes.progressBarWarning]: status === "warning",
[classes.progressBarError]: status === "error"
})}
style={{ ["--animationTime" as any]: `${autohide}ms` }}
/>
</div>
]}
/>
<MessageContext.Provider value={pushMessage}>
{children}
</MessageContext.Provider>
</>
);
};
export default MessageManager; export default MessageManager;

View file

@ -1,10 +1,12 @@
import { createContext } from "react"; import { createContext } from "react";
export interface IMessage { export interface IMessage {
action?: () => void;
autohide?: number; autohide?: number;
title?: string; title?: string;
text: string; text: string;
onUndo?: () => void; onUndo?: () => void;
status?: "success" | "error" | "info" | "warning";
} }
export type IMessageContext = (message: IMessage) => void; export type IMessageContext = (message: IMessage) => void;
export const MessageContext = createContext<IMessageContext>(undefined); export const MessageContext = createContext<IMessageContext>(undefined);

View file

@ -0,0 +1,114 @@
import errorIcon from "@assets/images/error-icon.svg";
import infoIcon from "@assets/images/info-icon.svg";
import successIcon from "@assets/images/success-icon.svg";
import warningIcon from "@assets/images/warning-icon.svg";
import { makeStyles } from "@material-ui/core/styles";
import { darken } from "@material-ui/core/styles/colorManipulator";
const successColor = "#60DAA0";
const warningColor = "#FFB84E";
const infoColor = "#CAD8DF";
export const useStyles = makeStyles(
theme => ({
"@keyframes bar": {
from: { transform: "translateX(-100%)" },
to: { transform: "translateX(0)" }
},
closeBtn: {
position: "absolute",
right: 0,
top: 0
},
error: {
"& > div": {
"& button span": {
color: "#fff"
},
"&:before": {
backgroundImage: `url(${errorIcon})`
},
backgroundColor: theme.palette.error.main,
color: "#fff"
}
},
progressBar: {
backgroundColor: infoColor,
height: 8,
transform: "translateX(-100%)",
width: "100%"
},
progressBarActive: {
animation: `$bar var(--animationTime) ease both`
},
progressBarContainer: {
borderRadius: "0 0 4px 4px",
bottom: 0,
left: 0,
overflow: "hidden",
position: "absolute",
width: "calc(100%)"
},
progressBarError: {
backgroundColor: darken(theme.palette.error.main, 0.2)
},
progressBarSuccess: {
backgroundColor: darken(successColor, 0.2)
},
progressBarWarning: {
backgroundColor: darken(warningColor, 0.2)
},
snackbar: {
"& > div": {
"&:before": {
backgroundImage: `url(${infoIcon})`,
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
content: "''",
display: "block",
height: 32,
left: 15,
position: "absolute",
top: 13,
width: 32
},
paddingLeft: 60,
position: "relative"
}
},
success: {
"& > div": {
"& button span": {
color: "#fff"
},
"&:before": {
backgroundImage: `url(${successIcon})`
},
backgroundColor: successColor,
color: "#fff"
}
},
text: {
color: "#fff",
paddingTop: 5
},
textInfo: {
paddingTop: 5
},
warning: {
"& > div": {
"& button span": {
color: "#fff"
},
"&:before": {
backgroundImage: `url(${warningIcon})`
},
backgroundColor: warningColor,
color: "#fff"
}
}
}),
{ name: "MessageManager" }
);

View file

@ -343,7 +343,9 @@ export default (colors: IThemeColors): Theme =>
color: colors.font.default color: colors.font.default
} }
}, },
alignSelf: "baseline" display: "block",
paddingBottom: 15,
paddingLeft: 0
}, },
message: { message: {
fontSize: 16 fontSize: 16
@ -353,8 +355,7 @@ export default (colors: IThemeColors): Theme =>
boxShadow: boxShadow:
"0 6px 10px 0px rgba(0, 0, 0, 0.15), 0 1px 18px 0px rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.10)", "0 6px 10px 0px rgba(0, 0, 0, 0.15), 0 1px 18px 0px rgba(0, 0, 0, 0.12), 0 3px 5px -1px rgba(0, 0, 0, 0.10)",
color: colors.font.default, color: colors.font.default,
display: "grid", display: "block",
gridTemplateColumns: "1fr 56px",
maxWidth: 480 maxWidth: 480
} }
}, },