From cb127d79869c89275b91b71b4ecb2ff2931c5b53 Mon Sep 17 00:00:00 2001 From: rkzel Date: Fri, 23 Aug 2019 18:06:29 +0200 Subject: [PATCH 1/2] tabbed Organization screen --- src/App.js | 1 - src/apps/Organization/Organization.js | 512 +++++++++++++------ src/assets/no-tokens-connected.png | Bin 0 -> 9470 bytes src/assets/organization-background.png | Bin 0 -> 7807 bytes src/assets/organization-logo-placeholder.png | Bin 0 -> 8562 bytes 5 files changed, 364 insertions(+), 149 deletions(-) create mode 100644 src/assets/no-tokens-connected.png create mode 100644 src/assets/organization-background.png create mode 100644 src/assets/organization-logo-placeholder.png diff --git a/src/App.js b/src/App.js index 6d54fb0eb..4b0d7ce9c 100644 --- a/src/App.js +++ b/src/App.js @@ -473,7 +473,6 @@ class App extends React.Component { /> - diff --git a/src/apps/Organization/Organization.js b/src/apps/Organization/Organization.js index 6cd71112b..546705973 100644 --- a/src/apps/Organization/Organization.js +++ b/src/apps/Organization/Organization.js @@ -1,13 +1,18 @@ -import React, { useCallback } from 'react' +import React, { useCallback, useState } from 'react' import PropTypes from 'prop-types' import { Box, Button, + Card, Header, IconCoin, Info, + Layout, Link, GU, + Tabs, + Text, + TextInput, textStyle, unselectable, useLayout, @@ -20,6 +25,189 @@ import { AppType, DaoAddressType, EthereumAddressType } from '../../prop-types' import providerString from '../../provider-strings' import airdrop, { testTokensEnabled } from '../../testnet/airdrop' import { toChecksumAddress } from '../../web3-utils' +import useAppWidth from '../useAppWidth' +import noTokensConnectedPNG from '../../assets/no-tokens-connected.png' +import organizationLogoPlaceholder from '../../assets/organization-logo-placeholder.png' +import organizationBackground from '../../assets/organization-background.png' +import styled from 'styled-components' + +const Address = ({ + checksummedDaoAddr, + shortAddresses, + depositFundsHelpText, +}) => ( +
+

+ {checksummedDaoAddr + ? `This organization is deployed on the Ethereum ${network.name}.` + : 'Resolving DAO address…'} +

+ {checksummedDaoAddr && ( + +
+ +
+ + + Do not send ETH or ERC20 tokens to this address. + {' '} + {depositFundsHelpText} + +
+ )} +
+) + +Address.propTypes = { + checksummedDaoAddr: PropTypes.string.isRequired, + shortAddresses: PropTypes.bool.isRequired, + depositFundsHelpText: PropTypes.string.isRequired, +} + +const RequestTokens = ({ + handleDepositTestTokens, + handleOpenFinanceApp, + enableTransactions, + walletNetwork, + walletProviderId, +}) => ( +
+

+ Deposit some tokens into your organization for testing purposes. +

+
+) + +RequestTokens.propTypes = { + handleDepositTestTokens: PropTypes.func.isRequired, + handleOpenFinanceApp: PropTypes.func.isRequired, + enableTransactions: PropTypes.bool.isRequired, + walletNetwork: PropTypes.string.isRequired, + walletProviderId: PropTypes.string.isRequired, +} + +const Apps = ({ appsLoading, apps, shortAddresses }) => { + const theme = useTheme() + const apmApps = apps.filter(app => !app.isAragonOsInternalApp) + + return appsLoading ? ( +
+
+ Loading apps… +
+
+ ) : ( +
+
    + {apmApps.map(({ appId, description, name, proxyAddress, tags }) => ( +
  • + +
    + +
    +
  • + ))} +
+
+ ) +} + +Apps.propTypes = { + apps: PropTypes.arrayOf(AppType).isRequired, + appsLoading: PropTypes.bool.isRequired, + shortAddresses: PropTypes.bool.isRequired, +} const Organization = React.memo(function Organization({ account, @@ -35,6 +223,7 @@ const Organization = React.memo(function Organization({ }) { const theme = useTheme() const { layoutName } = useLayout() + const [selectedTab, setSelectedTab] = useState(0) const handleDepositTestTokens = useCallback(() => { const finance = apps.find(app => app.appId === appIds.Finance) @@ -55,7 +244,6 @@ const Organization = React.memo(function Organization({ } }, [apps, onOpenApp]) - const apmApps = apps.filter(app => !app.isAragonOsInternalApp) const hasAgentApp = apps.some(app => app.appId === appIds.Agent) const hasFinanceApp = apps.some(app => app.appId === appIds.Finance) const checksummedDaoAddr = @@ -63,27 +251,6 @@ const Organization = React.memo(function Organization({ const enableTransactions = !!account && walletNetwork === network.type const shortAddresses = layoutName !== 'large' - const organizationText = checksummedDaoAddr ? ( - - This organization is deployed on the Ethereum {network.name}.{' '} - {canUpgradeOrg ? ( - - - A new software update is available - - . - - ) : ( - - The current software version is 0.8 Camino. You can see{' '} - what's new here. - - )} - - ) : ( - 'Resolving DAO address…' - ) - const depositFundsHelpText = appsLoading ? ( '' ) : hasFinanceApp || hasAgentApp ? ( @@ -105,148 +272,181 @@ const Organization = React.memo(function Organization({ return (
- -

- {organizationText} -

- {checksummedDaoAddr && ( - -
- -
- - - Do not send ETH or ERC20 tokens to this address. - {' '} - {depositFundsHelpText} - -
- )} -
- {hasFinanceApp && testTokensEnabled(network.type) && ( - -

- Deposit some tokens into your organization for testing purposes. -

- + + +
+
+
-
- - ))} - - + + Please keep 1:1 ratio +
+ +
+ + + + + +
+
+
+ + )} + {selectedTab === 2 && ( + +
+
+
+ )} + {selectedTab === 3 && ( + + +
+ + No tokens connected + Connect a token to your organization. + +
+
+
)} ) @@ -265,6 +465,22 @@ Organization.propTypes = { walletProviderId: PropTypes.string.isRequired, } +const Section = ({ ...props }) => { + return +} + const OpenAppButton = props => -export default Organization +const NoTokensCard = styled(Card)` + width: 100%; + height: 364px; +` + +export default props => { + const appWidth = useAppWidth() + return ( + + + + ) +} diff --git a/src/assets/no-tokens-connected.png b/src/assets/no-tokens-connected.png new file mode 100644 index 0000000000000000000000000000000000000000..3889f34f714ffd4d50c461bece7aab396ff7abb3 GIT binary patch literal 9470 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 literal 0 HcmV?d00001 From c7f4c851c60ccb3087558e917aa25a2d5d15c568 Mon Sep 17 00:00:00 2001 From: rkzel Date: Mon, 2 Sep 2019 23:16:07 +0200 Subject: [PATCH 2/2] brought styling to Figma design --- src/apps/Organization/Address.js | 52 ++++ src/apps/Organization/Apps.js | 69 +++++ src/apps/Organization/BasicInfo.js | 66 +++++ src/apps/Organization/Brand.js | 167 +++++++++++ src/apps/Organization/Label.js | 32 ++ src/apps/Organization/Organization.js | 389 +++---------------------- src/apps/Organization/RequestTokens.js | 90 ++++++ src/apps/Organization/Tokens.js | 277 ++++++++++++++++++ 8 files changed, 795 insertions(+), 347 deletions(-) create mode 100644 src/apps/Organization/Address.js create mode 100644 src/apps/Organization/Apps.js create mode 100644 src/apps/Organization/BasicInfo.js create mode 100644 src/apps/Organization/Brand.js create mode 100644 src/apps/Organization/Label.js create mode 100644 src/apps/Organization/RequestTokens.js create mode 100644 src/apps/Organization/Tokens.js diff --git a/src/apps/Organization/Address.js b/src/apps/Organization/Address.js new file mode 100644 index 000000000..229be3e18 --- /dev/null +++ b/src/apps/Organization/Address.js @@ -0,0 +1,52 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Box, Info, GU, textStyle } from '@aragon/ui' +import LocalIdentityBadge from '../../components/IdentityBadge/LocalIdentityBadge' +import { network } from '../../environment' + +const Address = ({ + checksummedDaoAddr, + shortAddresses, + depositFundsHelpText, +}) => ( + +

+ {checksummedDaoAddr + ? `This organization is deployed on the Ethereum ${network.name}.` + : 'Resolving DAO address…'} +

+ {checksummedDaoAddr && ( + +
+ +
+ + + Do not send ETH or ERC20 tokens to this address. + {' '} + {depositFundsHelpText} + +
+ )} +
+) + +Address.propTypes = { + checksummedDaoAddr: PropTypes.string.isRequired, + shortAddresses: PropTypes.bool.isRequired, + depositFundsHelpText: PropTypes.string.isRequired, +} + +export default Address diff --git a/src/apps/Organization/Apps.js b/src/apps/Organization/Apps.js new file mode 100644 index 000000000..576fe2fb6 --- /dev/null +++ b/src/apps/Organization/Apps.js @@ -0,0 +1,69 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { Box, GU, textStyle } from '@aragon/ui' +import LocalIdentityBadge from '../../components/IdentityBadge/LocalIdentityBadge' +import { AppType } from '../../prop-types' +import Label from './Label' + +const Apps = ({ appsLoading, apps, shortAddresses }) => { + const apmApps = apps.filter(app => !app.isAragonOsInternalApp) + + return appsLoading ? ( + +
+ Loading apps… +
+
+ ) : ( + +
    + {apmApps.map(({ appId, description, name, proxyAddress, tags }) => ( +
  • + +
    + +
    +
  • + ))} +
+
+ ) +} + +Apps.propTypes = { + apps: PropTypes.arrayOf(AppType).isRequired, + appsLoading: PropTypes.bool.isRequired, + shortAddresses: PropTypes.bool.isRequired, +} + +export default Apps diff --git a/src/apps/Organization/BasicInfo.js b/src/apps/Organization/BasicInfo.js new file mode 100644 index 000000000..0c8647fc0 --- /dev/null +++ b/src/apps/Organization/BasicInfo.js @@ -0,0 +1,66 @@ +import React, { useState } from 'react' +import { Box, Button, GU, TextInput } from '@aragon/ui' +import Label from './Label' + +const BasicInfo = () => { + const [basicInfo, setBasicInfo] = useState({ + name: '', + website: '', + description: '', + }) + + const changeBasicInfo = ({ target: { name, value } }) => { + const newBasicInfo = { ...basicInfo } + newBasicInfo[name] = value + setBasicInfo(newBasicInfo) + } + + const saveBasicInfo = () => { + console.log('save basic info:', basicInfo) + } + + return ( + +
+
+ +
+ +
+ +
+
+ +
+ +
+ + +
+ ) +} + +export default BasicInfo diff --git a/src/apps/Organization/Brand.js b/src/apps/Organization/Brand.js new file mode 100644 index 000000000..6ad0d9c6d --- /dev/null +++ b/src/apps/Organization/Brand.js @@ -0,0 +1,167 @@ +import React, { useState } from 'react' +import Dropzone from 'react-dropzone' +import { + Box, + Button, + DropDown, + GU, + Info, + Text, + TextInput, + useTheme, +} from '@aragon/ui' +import organizationLogoPlaceholder from '../../assets/organization-logo-placeholder.png' +import organizationBackground from '../../assets/organization-background.png' +import Label from './Label' + +const Brand = () => { + const theme = useTheme() + const [accentColor, setAccentColor] = useState('') + const [preferredTheme, setPreferredTheme] = useState(0) + const changePreferredTheme = index => setPreferredTheme(index) + const changeAccentColor = e => setAccentColor(e.target.value) + const saveColors = () => { + console.log('save accent color:', accentColor, 'theme:', preferredTheme) + } + const colorRX = /^#(([a-f0-9]{3}){1,2})$/i + const colorError = accentColor && !colorRX.test(accentColor) + + return ( + +
+
+
+ +
+
+
+ + +
+ ) +} + +export default Brand diff --git a/src/apps/Organization/Label.js b/src/apps/Organization/Label.js new file mode 100644 index 000000000..15e954f8b --- /dev/null +++ b/src/apps/Organization/Label.js @@ -0,0 +1,32 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { textStyle, unselectable, useTheme } from '@aragon/ui' + +const Label = ({ text, block, children }) => { + const theme = useTheme() + return ( + + ) +} + +Label.defaultProps = { + block: false, +} + +Label.propTypes = { + text: PropTypes.string.isRequired, + block: PropTypes.bool.isRequired, + children: PropTypes.node, +} + +export default Label diff --git a/src/apps/Organization/Organization.js b/src/apps/Organization/Organization.js index 546705973..7869cdea4 100644 --- a/src/apps/Organization/Organization.js +++ b/src/apps/Organization/Organization.js @@ -1,213 +1,17 @@ import React, { useCallback, useState } from 'react' import PropTypes from 'prop-types' -import { - Box, - Button, - Card, - Header, - IconCoin, - Info, - Layout, - Link, - GU, - Tabs, - Text, - TextInput, - textStyle, - unselectable, - useLayout, - useTheme, -} from '@aragon/ui' -import LocalIdentityBadge from '../../components/IdentityBadge/LocalIdentityBadge' +import { Box, Header, Layout, Link, GU, Tabs, useLayout } from '@aragon/ui' import { appIds, network } from '../../environment' -import { sanitizeNetworkType } from '../../network-config' import { AppType, DaoAddressType, EthereumAddressType } from '../../prop-types' -import providerString from '../../provider-strings' import airdrop, { testTokensEnabled } from '../../testnet/airdrop' import { toChecksumAddress } from '../../web3-utils' import useAppWidth from '../useAppWidth' -import noTokensConnectedPNG from '../../assets/no-tokens-connected.png' -import organizationLogoPlaceholder from '../../assets/organization-logo-placeholder.png' -import organizationBackground from '../../assets/organization-background.png' -import styled from 'styled-components' - -const Address = ({ - checksummedDaoAddr, - shortAddresses, - depositFundsHelpText, -}) => ( -
-

- {checksummedDaoAddr - ? `This organization is deployed on the Ethereum ${network.name}.` - : 'Resolving DAO address…'} -

- {checksummedDaoAddr && ( - -
- -
- - - Do not send ETH or ERC20 tokens to this address. - {' '} - {depositFundsHelpText} - -
- )} -
-) - -Address.propTypes = { - checksummedDaoAddr: PropTypes.string.isRequired, - shortAddresses: PropTypes.bool.isRequired, - depositFundsHelpText: PropTypes.string.isRequired, -} - -const RequestTokens = ({ - handleDepositTestTokens, - handleOpenFinanceApp, - enableTransactions, - walletNetwork, - walletProviderId, -}) => ( -
-

- Deposit some tokens into your organization for testing purposes. -

-
-) - -RequestTokens.propTypes = { - handleDepositTestTokens: PropTypes.func.isRequired, - handleOpenFinanceApp: PropTypes.func.isRequired, - enableTransactions: PropTypes.bool.isRequired, - walletNetwork: PropTypes.string.isRequired, - walletProviderId: PropTypes.string.isRequired, -} - -const Apps = ({ appsLoading, apps, shortAddresses }) => { - const theme = useTheme() - const apmApps = apps.filter(app => !app.isAragonOsInternalApp) - - return appsLoading ? ( -
-
- Loading apps… -
-
- ) : ( -
-
    - {apmApps.map(({ appId, description, name, proxyAddress, tags }) => ( -
  • - -
    - -
    -
  • - ))} -
-
- ) -} - -Apps.propTypes = { - apps: PropTypes.arrayOf(AppType).isRequired, - appsLoading: PropTypes.bool.isRequired, - shortAddresses: PropTypes.bool.isRequired, -} +import BasicInfo from './BasicInfo' +import Address from './Address' +import RequestTokens from './RequestTokens' +import Apps from './Apps' +import Brand from './Brand' +import Tokens from './Tokens' const Organization = React.memo(function Organization({ account, @@ -221,9 +25,10 @@ const Organization = React.memo(function Organization({ walletWeb3, walletProviderId, }) { - const theme = useTheme() const { layoutName } = useLayout() const [selectedTab, setSelectedTab] = useState(0) + const [tabsVisible, setTabsVisible] = useState(true) + const toggleTabsVisible = () => setTabsVisible(!tabsVisible) const handleDepositTestTokens = useCallback(() => { const finance = apps.find(app => app.appId === appIds.Finance) @@ -251,6 +56,22 @@ const Organization = React.memo(function Organization({ const enableTransactions = !!account && walletNetwork === network.type const shortAddresses = layoutName !== 'large' + const connectedTokens = [ + { + tokenName: 'Ethical Token', + tokenSymbol: 'ETC', + tokenDescription: + 'This is a token. It will do what tokens do, unless told otherwise. Then it will do something else.', + tokenAddress: '0x5Fef2867d4BbF1E7423Bb7FB9031402D4F99d2b0', + }, + { + tokenName: 'Unethical Token', + tokenSymbol: 'ETZ', + tokenDescription: 'This is a very unethical token.', + tokenAddress: '0x5Fef2867d4BbF1E7423Bb7FB9031402D4F99d2b0', + }, + ] + const depositFundsHelpText = appsLoading ? ( '' ) : hasFinanceApp || hasAgentApp ? ( @@ -273,11 +94,13 @@ const Organization = React.memo(function Organization({
- + {tabsVisible && ( + + )} {selectedTab === 0 && ( @@ -307,146 +130,23 @@ const Organization = React.memo(function Organization({ {selectedTab === 1 && ( -
-
-
- -
- -
- -
-
- -
- -
- - -
- -
-
-
- -
- -
- - Please keep 1:1 ratio -
- -
- - - - - -
-
-
+ +
)} + {selectedTab === 2 && ( -
-
+
+
)} + {selectedTab === 3 && ( - - -
- - No tokens connected - Connect a token to your organization. - -
-
-
+ )} ) @@ -471,11 +171,6 @@ const Section = ({ ...props }) => { const OpenAppButton = props => -const NoTokensCard = styled(Card)` - width: 100%; - height: 364px; -` - export default props => { const appWidth = useAppWidth() return ( diff --git a/src/apps/Organization/RequestTokens.js b/src/apps/Organization/RequestTokens.js new file mode 100644 index 000000000..90bf77471 --- /dev/null +++ b/src/apps/Organization/RequestTokens.js @@ -0,0 +1,90 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { + Box, + Button, + ButtonText, + IconCoin, + Info, + GU, + textStyle, +} from '@aragon/ui' +import { network } from '../../environment' +import { sanitizeNetworkType } from '../../network-config' +import providerString from '../../provider-strings' + +const OpenAppButton = props => ( + +) + +const RequestTokens = ({ + handleDepositTestTokens, + handleOpenFinanceApp, + enableTransactions, + walletNetwork, + walletProviderId, +}) => ( + +

+ Deposit some tokens into your organization for testing purposes. +

+ + + +) + +const TokenDetails = ({ token }) => { + const theme = useTheme() + const { layoutName } = useLayout() + const [removeDialogOpen, setRemoveDialogOpen] = useState(false) + const oneColumn = layoutName === 'small' + const toggleRemoveDialog = () => setRemoveDialogOpen(!removeDialogOpen) + + return ( + + + + Remove token + + + This action will remove your token from the organization, until you + decide to reconnect it. + +
+ + +
+
+ + +
+
+
+
+
+
+
+ +
+
+ +
+
+ +
+ + +
+
+ +
+ console.log(acceptedFiles)}> + {({ getRootProps, getInputProps, isDragActive }) => ( +
+ +
+ +
+ + Please keep 1:1 ratio +
+ )} +
+
+
+
+ ) +} + +TokenDetails.propTypes = { + token: PropTypes.object.isRequired, +} + +const Tokens = ({ connectedTokens, toggleTabsVisible }) => { + const { layoutName } = useLayout() + const theme = useTheme() + const [currentToken, setCurrentToken] = useState(-1) + const compactMode = layoutName === 'small' + const rowHeight = compactMode ? null : 350 + + if (connectedTokens.length === 0) { + return + } + + if (currentToken > -1) { + return ( + + + { + setCurrentToken(-1) + toggleTabsVisible() + }} + /> + + + + ) + } + + return ( + + {connectedTokens.map((token, i) => { + const handleOpen = () => { + setCurrentToken(i) + toggleTabsVisible() + } + + return ( + + + + {token.tokenName}{' '} + + ({token.tokenSymbol}) + + + + + ) + })} + + ) +} +Tokens.propTypes = { + connectedTokens: PropTypes.arrayOf(PropTypes.object).isRequired, + toggleTabsVisible: PropTypes.func.isRequired, +} + +const NoTokensCard = styled(Card)` + width: 100%; + height: 364px; +` +const TokenDetailsCard = styled(Card)` + width: 100%; + height: unset; +` + +export default Tokens