Skip to content

Commit

Permalink
New error display element in header (#336)
Browse files Browse the repository at this point in the history
* New error display element in header

* The new header contains a status icon displaying if any errors / warnings exist
* on click it opens the message display
* the message provider was reworked to be more consistent
* the submit button turns red and changes its label if there are any existing errors

Other:
* Fixes mergify config
  • Loading branch information
schmanu authored Jan 12, 2022
1 parent bf6025f commit e93c7ab
Show file tree
Hide file tree
Showing 8 changed files with 128 additions and 46 deletions.
16 changes: 11 additions & 5 deletions .mergify.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
queue_rules:
- name: default
conditions:
# Conditions to get out of the queue (= merged)
- check-success=^test \([0-9]+\.x, ubuntu-latest\)$

pull_request_rules:
- name: Merge approved and green PRs with `merge when green` label
conditions:
Expand All @@ -6,10 +12,10 @@ pull_request_rules:
- base=master
- label=merge when green
actions:
merge:
queue:
method: squash
strict: smart+fasttrack
commit_message: title+body
name: default
- name: Automatic merge for Dependabot pull requests
conditions:
- author~=^dependabot(|-preview)\[bot\]$
Expand All @@ -18,8 +24,8 @@ pull_request_rules:
actions:
review:
type: APPROVE
message: Automatically approving dependabot
merge:
message: Automatically approving dependabo
queue:
method: squash
strict: smart+fasttrack
commit_message: title+body
name: default
16 changes: 11 additions & 5 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ import { useSafeAppsSDK } from "@gnosis.pm/safe-apps-react-sdk";
import { BaseTransaction } from "@gnosis.pm/safe-apps-sdk";
import { Breadcrumb, BreadcrumbElement, Button, Card, Divider, Loader, Text } from "@gnosis.pm/safe-react-components";
import { setUseWhatChange } from "@simbathesailor/use-what-changed";
import React, { useCallback, useState } from "react";
import React, { useCallback, useState, useContext } from "react";
import styled from "styled-components";

import { CSVForm } from "./components/CSVForm";
import { FAQModal } from "./components/FAQModal";
import { Header } from "./components/Header";
import { Summary } from "./components/Summary";
import { MessageContext } from "./contexts/MessageContextProvider";
import { useBalances } from "./hooks/balances";
import { useTokenList } from "./hooks/token";
import { AssetTransfer, CollectibleTransfer, Transfer } from "./parser/csvParser";
Expand All @@ -20,6 +20,7 @@ const App: React.FC = () => {
const { isLoading } = useTokenList();
const balanceLoader = useBalances();
const [tokenTransfers, setTokenTransfers] = useState<Transfer[]>([]);
const { messages } = useContext(MessageContext);

const [submitting, setSubmitting] = useState(false);
const [parsing, setParsing] = useState(false);
Expand Down Expand Up @@ -95,18 +96,23 @@ const App: React.FC = () => {
<Button
style={{ alignSelf: "flex-start", marginTop: 16, marginBottom: 16 }}
size="lg"
color="primary"
color={messages.length === 0 ? "primary" : "error"}
onClick={submitTx}
disabled={parsing || tokenTransfers.length + collectibleTransfers.length === 0}
>
{parsing ? <Loader size="sm" color="primaryLight" /> : "Submit"}
{parsing ? (
<Loader size="sm" color="primaryLight" />
) : messages.length === 0 ? (
"Submit"
) : (
"Submit with errors"
)}
</Button>
)}
</Card>
)}
</>
}
<FAQModal />
</Container>
);
};
Expand Down
19 changes: 19 additions & 0 deletions src/GlobalStyle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,25 @@ const GlobalStyle = createGlobalStyle`
background-color: rgb(247, 245, 245);
border-radius: 8px;
}
.MuiFab-root.statusDotButtonEmpty {
background-color: #4caf50;
}
.MuiFab-root.statusDotButtonEmpty:hover {
background-color: #2e7d32;
cursor: pointer;
}
.MuiFab-root.statusDotButtonErrors {
background-color: #ef5350;
}
.MuiFab-root.statusDotButtonErrors:hover {
background-color: #d32f2f;
cursor: pointer;
}
`;

export default GlobalStyle;
4 changes: 2 additions & 2 deletions src/components/CSVForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ export const CSVForm = (props: CSVFormProps): JSX.Element => {
) {
return {
message: `Insufficient Balance: ${insufficientBalanceInfo.transferAmount} of ${insufficientBalanceInfo.token}`,
severity: "warning",
severity: "error",
};
} else {
if (insufficientBalanceInfo.isDuplicate) {
Expand All @@ -93,7 +93,7 @@ export const CSVForm = (props: CSVFormProps): JSX.Element => {
} else {
return {
message: `Collectible ERC721 token ${insufficientBalanceInfo.token} with ID ${insufficientBalanceInfo.id} is not held by this safe`,
severity: "warning",
severity: "error",
};
}
}
Expand Down
7 changes: 1 addition & 6 deletions src/components/FAQModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,7 @@ export const FAQModal: () => JSX.Element = () => {
const [showHelp, setShowHelp] = useState(false);
return (
<>
<Fab
variant="extended"
size="small"
style={{ position: "absolute", top: 24, right: 24, textTransform: "none" }}
onClick={() => setShowHelp(true)}
>
<Fab variant="extended" size="small" style={{ textTransform: "none" }} onClick={() => setShowHelp(true)}>
<Icon size="md" type="question" />
<Text size="xl">Help</Text>
</Fab>
Expand Down
81 changes: 57 additions & 24 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,26 @@
import { Snackbar } from "@material-ui/core";
import { Icon, Text } from "@gnosis.pm/safe-react-components";
import { Fab, Snackbar } from "@material-ui/core";
import MuiAlert from "@material-ui/lab/Alert";
import React, { useContext } from "react";
import styled from "styled-components";

import { MessageContext, Message } from "../contexts/MessageContextProvider";

import { FAQModal } from "./FAQModal";

export function Alert(props) {
return <MuiAlert elevation={6} variant="filled" {...props} />;
}
const HeaderContainer = styled.div`
flex: 1;
width: 100%;
position: absolute;
justify-content: flex-end;
display: flex;
top: 24px;
right: 24px;
z-index: 2;
gap: 8px;
`;

const AlertWrapper = styled.div`
Expand All @@ -22,31 +32,54 @@ const AlertWrapper = styled.div`
`;

export const Header = (): JSX.Element => {
const messageContext = useContext(MessageContext);
const messages = messageContext.messages;
const { messages, showMessages, hideMessages, toggleMessages, removeMessage } = useContext(MessageContext);

const handleClose = (event: React.SyntheticEvent | Event, reason?: string) => {
if (reason === "clickaway") {
return;
}

hideMessages();
};

return (
<HeaderContainer>
{messages?.length > 0 && (
<Snackbar
anchorOrigin={{ vertical: "top", horizontal: "right" }}
open={messages?.length > 0}
onClose={() => messageContext.setMessages([])}
autoHideDuration={6000}
style={{ gap: "4px" }}
>
<AlertWrapper>
{messages.map((message: Message, index: number) => (
<Alert
severity={message.severity}
key={"message" + index}
onClose={() => messageContext.removeMessage(message)}
>
{message.message}
</Alert>
))}
</AlertWrapper>
</Snackbar>
)}
<Fab
variant="circular"
size="small"
className={messages.length === 0 ? "statusDotButtonEmpty" : "statusDotButtonErrors"}
style={{ textTransform: "none", width: "34px", height: "34px" }}
onClick={toggleMessages}
>
{messages.length === 0 ? (
<Icon color="white" type="check" size="sm" />
) : (
<Text size="xl" color="white">
{messages.length}
</Text>
)}
</Fab>
<FAQModal />
<Snackbar
anchorOrigin={{ vertical: "top", horizontal: "right" }}
open={showMessages}
onClose={handleClose}
autoHideDuration={6000}
style={{ gap: "4px", top: "64px" }}
>
<AlertWrapper>
{messages.length === 0 && (
<Alert secerity="success" key="successMessage">
No warnings or errors.
</Alert>
)}
{messages.map((message: Message, index: number) => (
<Alert severity={message.severity} key={"message" + index} onClose={() => removeMessage(message)}>
{message.message}
</Alert>
))}
</AlertWrapper>
</Snackbar>
</HeaderContainer>
);
};
29 changes: 26 additions & 3 deletions src/contexts/MessageContextProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, ReactElement } from "react";
import React, { useState, ReactElement, useCallback } from "react";

export type CodeWarning = {
message: string;
Expand All @@ -18,6 +18,9 @@ type MessageContextType = {
addMessage: (message: Message) => void;
codeWarnings: CodeWarning[];
setCodeWarnings: (messages: CodeWarning[]) => void;
showMessages: boolean;
hideMessages: () => void;
toggleMessages: () => void;
};

export const MessageContext = React.createContext<MessageContextType>({
Expand All @@ -27,18 +30,31 @@ export const MessageContext = React.createContext<MessageContextType>({
addMessage: (message: Message | CodeWarning) => {},
codeWarnings: [],
setCodeWarnings: (messages: CodeWarning[]) => {},
showMessages: false,
hideMessages: () => {},
toggleMessages: () => {},
});

type MessageContextProviderProps = {
children: ReactElement;
};

export const MessageContextProvider = (props: MessageContextProviderProps) => {
const [messages, setMessages] = useState<Message[]>([]);
const [messages, internalSetMessages] = useState<Message[]>([]);
const [codeWarnings, setCodeWarnings] = useState<CodeWarning[]>([]);
const [showMessages, setShowMessages] = useState(false);

const removeMessage = (messageToRemove: Message | CodeWarning) =>
const removeMessage = (messageToRemove: Message | CodeWarning) => {
console.log("Removing Message");
setMessages(messages.filter((message) => message.message !== messageToRemove.message));
};

const setMessages = useCallback((newMessages: Message[]) => {
internalSetMessages(newMessages);
if (newMessages.length > 0) {
setShowMessages(true);
}
}, []);

const addMessage = (messageToAdd: Message | CodeWarning) => {
// Do not add equal message
Expand All @@ -47,13 +63,20 @@ export const MessageContextProvider = (props: MessageContextProviderProps) => {
}
};

const hideMessages = () => setShowMessages(false);

const toggleMessages = () => setShowMessages(!showMessages);

const contextValue = {
messages,
setMessages,
removeMessage,
addMessage,
codeWarnings,
setCodeWarnings,
showMessages,
hideMessages,
toggleMessages,
};

return <MessageContext.Provider value={contextValue}>{props.children}</MessageContext.Provider>;
Expand Down
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6520,7 +6520,7 @@ eslint-plugin-react-hooks@^4.2.0, eslint-plugin-react-hooks@^4.3.0:
resolved "https://registry.yarnpkg.com/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.3.0.tgz#318dbf312e06fab1c835a4abef00121751ac1172"
integrity sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==

eslint-plugin-react@^7.21.5, eslint-plugin-react@^7.28.0:
eslint-plugin-react@^7.21.5, eslint-plugin-react@^7.27.1, eslint-plugin-react@^7.28.0:
version "7.28.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz#8f3ff450677571a659ce76efc6d80b6a525adbdf"
integrity sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==
Expand Down

0 comments on commit e93c7ab

Please sign in to comment.