Skip to content

Commit

Permalink
feat: redesign app (bh2smith#491)
Browse files Browse the repository at this point in the history
* feat: redesign app

Update safe-react-components and use the new theme to redesign the app.
This requires an update of MUI to v5 and removes styled-components.
All wrapped MUI components were removed meaning that we have to use the native MUI components across the app.

Improvements:
- Uses dark mode if OS of user is set to dark appearance
- Improves design / flow of the app

* fix: table border colors, drain dialog address validation
  • Loading branch information
schmanu authored Feb 24, 2023
1 parent ad31bc7 commit 33f14af
Show file tree
Hide file tree
Showing 49 changed files with 1,444 additions and 1,220 deletions.
22 changes: 14 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,20 @@
"postinstall": "yarn generate-types"
},
"dependencies": {
"@gnosis.pm/safe-apps-provider": "^0.15.1",
"@gnosis.pm/safe-apps-react-sdk": "^4.6.1",
"@gnosis.pm/safe-apps-sdk": "^7.7.0",
"@gnosis.pm/safe-react-components": "1.1.5",
"@material-ui/core": "^4.12.3",
"@material-ui/lab": "^4.0.0-alpha.60",
"@emotion/cache": "^11.10.1",
"@emotion/react": "^11.10.0",
"@emotion/server": "^11.10.0",
"@emotion/styled": "^11.10.0",
"@gnosis.pm/safe-react-gateway-sdk": "^3.5.2",
"@mui/icons-material": "^5.8.4",
"@mui/material": "^5.11.2",
"@mui/styles": "^5.11.9",
"@openzeppelin/contracts": "^4.8.1",
"@reduxjs/toolkit": "^1.8.1",
"@safe-global/safe-apps-provider": "^0.16.0",
"@safe-global/safe-apps-react-sdk": "^4.6.4",
"@safe-global/safe-apps-sdk": "^7.10.0",
"@safe-global/safe-react-components": "2.0.3",
"ace-builds": "^1.15.0",
"bignumber.js": "^9.0.2",
"ethers": "^5.7.2",
Expand All @@ -41,12 +47,12 @@
"react-svg": "^15.1.7",
"react-virtualized-auto-sizer": "^1.0.6",
"react-window": "^1.8.8",
"styled-components": "^5.3.6",
"tslib": "^2.4.1",
"typescript": "~4.4.4"
},
"devDependencies": {
"@simbathesailor/use-what-changed": "^2.0.0",
"@svgr/webpack": "^6.5.1",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^12.1.3",
"@testing-library/react-hooks": "^8.0.1",
Expand All @@ -57,7 +63,6 @@
"@types/react-dom": "^18.0.3",
"@types/react-virtualized-auto-sizer": "^1.0.1",
"@types/react-window": "^1.8.5",
"@types/styled-components": "^5.1.23",
"babel-eslint": "^10.1.0",
"eslint-config-prettier": "^8.5.0",
"eslint-config-react-app": "^7.0.0",
Expand All @@ -67,6 +72,7 @@
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0",
"husky": "^8.0.1",
"postcss-normalize": "^10.0.1",
"prettier": "^2.8.3",
"pretty-quick": "^3.1.3",
"react-scripts": "^5.0.1",
Expand Down
143 changes: 82 additions & 61 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,29 +1,30 @@
import { useSafeAppsSDK } from "@gnosis.pm/safe-apps-react-sdk";
import { BaseTransaction, GatewayTransactionDetails } from "@gnosis.pm/safe-apps-sdk";
import { Breadcrumb, BreadcrumbElement, Button, Card, Divider, Loader } from "@gnosis.pm/safe-react-components";
import { setUseWhatChange } from "@simbathesailor/use-what-changed";
import { Box, Button, Card, CircularProgress, Grid, Typography, useTheme } from "@mui/material";
import { useSafeAppsSDK } from "@safe-global/safe-apps-react-sdk";
import { BaseTransaction, GatewayTransactionDetails } from "@safe-global/safe-apps-sdk";
import React, { useCallback, useEffect, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Unsubscribe } from "redux";
import styled from "styled-components";

import { CSVForm } from "./components/CSVForm";
import { Header } from "./components/Header";
import { FAQModal } from "./components/FAQModal";
import { Loading } from "./components/Loading";
import { Summary } from "./components/Summary";
import { TransactionStatusScreen } from "./components/TransactionStatusScreen";
import { useEnsResolver } from "./hooks/ens";
import { useTokenList } from "./hooks/token";
import { AssetTransfer, CollectibleTransfer, useCsvParser } from "./hooks/useCsvParser";
import { useEnsResolver } from "./hooks/useEnsResolver";
import CheckIcon from "./static/check.svg";
import AppIcon from "./static/logo.svg";
import { useGetAssetBalanceQuery, useGetAllNFTsQuery } from "./stores/api/balanceApi";
import { setupParserListener } from "./stores/middleware/parseListener";
import { setSafeInfo } from "./stores/slices/safeInfoSlice";
import { RootState, startAppListening } from "./stores/store";
import { buildAssetTransfers, buildCollectibleTransfers } from "./transfers/transfers";

setUseWhatChange(process.env.NODE_ENV === "development");
import "./styles/globals.css";

const App: React.FC = () => {
const theme = useTheme();
const { isLoading } = useTokenList();
const { sdk, safe } = useSafeAppsSDK();
const assetBalanceQuery = useGetAssetBalanceQuery();
Expand Down Expand Up @@ -65,62 +66,82 @@ const App: React.FC = () => {
}, [assetTransfers, collectibleTransfers, sdk.txs]);

return (
<Container>
<Header />
{
<>
{isLoading || assetBalanceQuery.isLoading || nftBalanceQuery.isLoading ? (
<Loading />
) : (
<Card className="cardWithCustomShadow">
{!pendingTx && (
<>
<Breadcrumb>
<BreadcrumbElement text="CSV Transfer File" iconType="paste" />
</Breadcrumb>
<CSVForm />
<Divider />
</>
)}
<Breadcrumb>
<BreadcrumbElement text="Summary" iconType="transactionsInactive" />
<BreadcrumbElement text="Transfers" color="placeHolder" />
</Breadcrumb>
<Summary assetTransfers={assetTransfers} collectibleTransfers={collectibleTransfers} />
{pendingTx ? (
<TransactionStatusScreen tx={pendingTx} reset={() => setPendingTx(undefined)} />
) : (
<Button
style={{ alignSelf: "flex-start", marginTop: 16, marginBottom: 16 }}
size="lg"
color={messages.length === 0 ? "primary" : "error"}
onClick={submitTx}
disabled={parsing || transfers.length + collectibleTransfers.length === 0}
>
{parsing ? (
<Loader size="sm" color="primaryLight" />
) : messages.length === 0 ? (
"Submit"
<Box
sx={{
maxWidth: "950px",
paddingTop: "24px",
position: "relative",
margin: "auto",
}}
>
<Box display="flex" flexDirection="column" justifyContent="left">
{
<>
{isLoading || assetBalanceQuery.isLoading || nftBalanceQuery.isLoading ? (
<Loading />
) : (
<Box display="flex" flexDirection="column" gap={2}>
<Grid container>
<Grid item xs={4}>
<Box>
<Typography mb={2} variant="h3" fontWeight={700} display="flex" alignItems="center" gap={1}>
<img src={AppIcon} width="32px" height="32px" alt="logo" /> CSV Airdrop
</Typography>
<FAQModal />
</Box>
</Grid>
<Grid item xs display="flex" direction="row" alignItems="center" gap={2}>
<img
src={CheckIcon}
alt="check"
width={24}
height={24}
style={{ background: theme.palette.background.light, borderRadius: "12px" }}
/>
<Typography>
Send arbitrarily many distinct tokens, to arbitrarily many distinct accounts with various
different values from a CSV file in a single transaction.
</Typography>
</Grid>
</Grid>

{!pendingTx && (
<Card sx={{ padding: 2, mt: 3 }}>
<CSVForm />
</Card>
)}
<Card sx={{ padding: 2 }}>
<Summary assetTransfers={assetTransfers} collectibleTransfers={collectibleTransfers} />
{pendingTx ? (
<TransactionStatusScreen tx={pendingTx} reset={() => setPendingTx(undefined)} />
) : (
"Submit with errors"
<Button
variant="contained"
style={{ alignSelf: "flex-start", marginTop: 16, marginBottom: 16 }}
size="stretched"
color={messages.length === 0 ? "primary" : "error"}
onClick={submitTx}
disabled={parsing || transfers.length + collectibleTransfers.length === 0}
>
{parsing ? (
<>
<CircularProgress size="small" color="secondary" /> Parsing
</>
) : messages.length === 0 ? (
"Submit"
) : (
"Submit with errors"
)}
</Button>
)}
</Button>
)}
</Card>
)}
</>
}
</Container>
</Card>
</Box>
)}
</>
}
</Box>
</Box>
);
};

const Container = styled.div`
margin-left: 16px;
display: flex;
flex-direction: column;
flex: 1;
justify-content: left;
width: 100%;
`;

export default App;
52 changes: 52 additions & 0 deletions src/AppWrapper.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { CircularProgress, CssBaseline, GlobalStyles, Theme, ThemeProvider, Typography } from "@mui/material";
import SafeProvider from "@safe-global/safe-apps-react-sdk";
import { SafeThemeProvider } from "@safe-global/safe-react-components";
import { Provider as ReduxProvider } from "react-redux";

import App from "./App";
import { useDarkMode } from "./hooks/useDarkMode";
import errorIcon from "./static/error-icon.svg";
import { store } from "./stores/store";

export const AppWrapper = () => {
const isDarkMode = useDarkMode();
const themeMode = isDarkMode ? "dark" : "light";

return (
<SafeThemeProvider mode={themeMode}>
{(safeTheme: Theme) => (
<ThemeProvider theme={safeTheme}>
<CssBaseline />
<GlobalStyles
styles={{
".error-marker": {
position: "absolute",
backgroundColor: "lightpink",
display: "block",
},
".ace_error": {
backgroundImage: `url(${errorIcon}) !important`,
backgroundSize: "15px",
},
".ace_tooltip.ace_error": {
backgroundImage: "none !important",
},
}}
/>
<SafeProvider
loader={
<>
<Typography>Waiting for Safe...</Typography>
<CircularProgress />
</>
}
>
<ReduxProvider store={store}>
<App />
</ReduxProvider>
</SafeProvider>
</ThemeProvider>
)}
</SafeThemeProvider>
);
};
Loading

0 comments on commit 33f14af

Please sign in to comment.