-
Notifications
You must be signed in to change notification settings - Fork 357
SafeApps new layout #1600
SafeApps new layout #1600
Changes from all commits
115fd39
fac9409
f03a901
89d30af
8e14c48
8730750
45c6b95
0ac4c03
c16d66f
7443571
1220f6c
8a2412d
1fbb740
fc2d00a
c160095
da31053
1562e10
164d7ce
3c235c4
510d0a7
514f683
133b987
1f00af2
673e920
4350492
2e84d1d
1c2a833
d1f2acf
49accc9
1188732
fdbcd99
7b2db47
81b93bd
dade47e
81284b3
c518f11
5b81c6e
00db2e8
f0f4da4
421c7a4
2d6fd85
1fbb83d
19762f1
a121c17
210358b
3613122
2937fb4
7aa55b4
497ada5
3dac823
60b9ef9
3dd6d67
8442d2b
5b0f390
44b3875
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| import styled from 'styled-components' | ||
|
|
||
| export const LoadingContainer = styled.div` | ||
| width: 100%; | ||
| height: 100%; | ||
| display: flex; | ||
| align-items: center; | ||
| justify-content: center; | ||
| ` |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,51 @@ | ||
| import { Button, Divider } from '@gnosis.pm/safe-react-components' | ||
| import React, { ReactElement, useMemo } from 'react' | ||
| import { useFormState } from 'react-final-form' | ||
| import styled from 'styled-components' | ||
|
|
||
| import GnoButton from 'src/components/layout/Button' | ||
| import { SafeApp } from 'src/routes/safe/components/Apps/types.d' | ||
| import { isAppManifestValid } from 'src/routes/safe/components/Apps/utils' | ||
|
|
||
| const StyledDivider = styled(Divider)` | ||
| margin: 16px -24px; | ||
| ` | ||
|
|
||
| const ButtonsContainer = styled.div` | ||
| display: flex; | ||
| justify-content: space-between; | ||
| ` | ||
|
|
||
| interface Props { | ||
| appInfo: SafeApp | ||
| onCancel: () => void | ||
| } | ||
|
|
||
| const FormButtons = ({ appInfo, onCancel }: Props): ReactElement => { | ||
| const { valid, validating, visited } = useFormState({ | ||
| subscription: { valid: true, validating: true, visited: true }, | ||
| }) | ||
|
|
||
| const isSubmitDisabled = useMemo(() => { | ||
| // if non visited, fields were not evaluated yet. Then, the default value is considered invalid | ||
| const fieldsVisited = visited?.agreementAccepted && visited?.appUrl | ||
|
|
||
| return validating || !valid || !fieldsVisited || !isAppManifestValid(appInfo) | ||
| }, [validating, valid, visited, appInfo]) | ||
|
|
||
| return ( | ||
| <> | ||
| <StyledDivider /> | ||
| <ButtonsContainer> | ||
| <Button size="md" onClick={onCancel} color="secondary"> | ||
| Cancel | ||
| </Button> | ||
| <GnoButton color="primary" variant="contained" type="submit" disabled={isSubmitDisabled}> | ||
| Add | ||
| </GnoButton> | ||
| </ButtonsContainer> | ||
| </> | ||
| ) | ||
| } | ||
|
|
||
| export default FormButtons | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,19 +1,20 @@ | ||
| import { Text, TextField } from '@gnosis.pm/safe-react-components' | ||
| import React from 'react' | ||
| import { TextField } from '@gnosis.pm/safe-react-components' | ||
| import React, { useState, ReactElement } from 'react' | ||
| import styled from 'styled-components' | ||
|
|
||
| import AppAgreement from './AppAgreement' | ||
| import AppUrl, { AppInfoUpdater, appUrlResolver } from './AppUrl' | ||
| import SubmitButtonStatus from './SubmitButtonStatus' | ||
|
|
||
| import { SafeApp } from 'src/routes/safe/components/Apps/types.d' | ||
| import GnoForm from 'src/components/forms/GnoForm' | ||
| import Img from 'src/components/layout/Img' | ||
| import appsIconSvg from 'src/routes/safe/components/Transactions/TxsTable/TxType/assets/appsIcon.svg' | ||
|
|
||
| const StyledText = styled(Text)` | ||
| margin-bottom: 19px; | ||
| ` | ||
| import AppAgreement from './AppAgreement' | ||
| import AppUrl, { AppInfoUpdater, appUrlResolver } from './AppUrl' | ||
| import FormButtons from './FormButtons' | ||
| import { APPS_STORAGE_KEY, getEmptySafeApp } from 'src/routes/safe/components/Apps/utils' | ||
| import { saveToStorage } from 'src/utils/storage' | ||
| import { SAFELIST_ADDRESS } from 'src/routes/routes' | ||
| import { useHistory, useRouteMatch } from 'react-router-dom' | ||
|
|
||
| const FORM_ID = 'add-apps-form' | ||
|
|
||
| const StyledTextFileAppName = styled(TextField)` | ||
| && { | ||
|
|
@@ -39,38 +40,34 @@ const INITIAL_VALUES: AddAppFormValues = { | |
| agreementAccepted: false, | ||
| } | ||
|
|
||
| const APP_INFO: SafeApp = { | ||
| id: '', | ||
| url: '', | ||
| name: '', | ||
| iconUrl: appsIconSvg, | ||
| error: false, | ||
| description: '', | ||
| } | ||
| const APP_INFO = getEmptySafeApp() | ||
|
|
||
| interface AddAppProps { | ||
| appList: SafeApp[] | ||
| closeModal: () => void | ||
| formId: string | ||
| onAppAdded: (app: SafeApp) => void | ||
| setIsSubmitDisabled: (disabled: boolean) => void | ||
| } | ||
|
|
||
| const AddApp = ({ appList, closeModal, formId, onAppAdded, setIsSubmitDisabled }: AddAppProps): React.ReactElement => { | ||
| const [appInfo, setAppInfo] = React.useState<SafeApp>(APP_INFO) | ||
| const AddApp = ({ appList, closeModal }: AddAppProps): ReactElement => { | ||
| const [appInfo, setAppInfo] = useState<SafeApp>(APP_INFO) | ||
| const history = useHistory() | ||
| const matchSafeWithAddress = useRouteMatch<{ safeAddress: string }>({ path: `${SAFELIST_ADDRESS}/:safeAddress` }) | ||
|
|
||
| const handleSubmit = () => { | ||
| closeModal() | ||
| onAppAdded(appInfo) | ||
| const newAppList = [ | ||
| { url: appInfo.url, disabled: false }, | ||
| ...appList.map(({ url, disabled }) => ({ url, disabled })), | ||
| ] | ||
| saveToStorage(APPS_STORAGE_KEY, newAppList) | ||
| const goToApp = `${matchSafeWithAddress?.url}/apps?appUrl=${encodeURI(appInfo.url)}` | ||
| history.push(goToApp) | ||
| } | ||
|
Comment on lines
55
to
63
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This only updates the stored app list and not app's state, is it intended?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. sorry, what do you mean by app's state?
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we hold an apps list in state inside useAppList hook
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ahh, I see what you mean. No, it's not needed anymore, because the useAppList is only used in /apps URL, when we add a new app, we redirect it to /apps/new_app_url. |
||
|
|
||
| return ( | ||
| <GnoForm decorators={[appUrlResolver]} initialValues={INITIAL_VALUES} onSubmit={handleSubmit} testId={formId}> | ||
| <GnoForm decorators={[appUrlResolver]} initialValues={INITIAL_VALUES} onSubmit={handleSubmit} testId={FORM_ID}> | ||
| {() => ( | ||
| <> | ||
| <StyledText size="xl">Add custom app</StyledText> | ||
|
|
||
| <AppUrl appList={appList} /> | ||
|
|
||
| {/* Fetch app from url and return a SafeApp */} | ||
| <AppInfoUpdater onAppInfo={setAppInfo} /> | ||
|
|
||
|
|
@@ -81,7 +78,7 @@ const AddApp = ({ appList, closeModal, formId, onAppAdded, setIsSubmitDisabled } | |
|
|
||
| <AppAgreement /> | ||
|
|
||
| <SubmitButtonStatus onSubmitButtonStatusChange={setIsSubmitDisabled} appInfo={appInfo} /> | ||
| <FormButtons appInfo={appInfo} onCancel={closeModal} /> | ||
| </> | ||
| )} | ||
| </GnoForm> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import React from 'react' | ||
|
|
||
| import AppCard from './index' | ||
|
|
||
| import AddAppIcon from 'src/routes/safe/components/Apps/assets/addApp.svg' | ||
|
|
||
| export default { | ||
| title: 'Apps/AppCard', | ||
| component: AppCard, | ||
| } | ||
|
|
||
| export const Loading = (): React.ReactElement => <AppCard isLoading /> | ||
|
|
||
| export const AddCustomApp = (): React.ReactElement => ( | ||
| <AppCard iconUrl={AddAppIcon} onClick={console.log} buttonText="Add custom app" /> | ||
| ) | ||
|
|
||
| export const LoadedApp = (): React.ReactElement => ( | ||
| <AppCard | ||
| iconUrl="https://cryptologos.cc/logos/versions/gnosis-gno-gno-logo-circle.svg?v=007" | ||
| name="Gnosis" | ||
| description="Gnosis safe app" | ||
| onClick={console.log} | ||
| /> | ||
| ) |
Uh oh!
There was an error while loading. Please reload this page.