From df803f00e64909d4bdceccfcd8345b64b1dc6207 Mon Sep 17 00:00:00 2001 From: Andre Neves Date: Thu, 30 May 2019 21:52:24 -0400 Subject: [PATCH 01/12] type(flow): update flowtype badge From 1646f2b6ef7df57bf4126a7c1ba4745b9227476a Mon Sep 17 00:00:00 2001 From: SamPatt Date: Fri, 31 May 2019 11:24:48 -0400 Subject: [PATCH 02/12] Clarify transparent address sublabel The original text "By using transaparent addresses you are forgiving any privacy properties to your transactions" contains a typo and the word "forgiving" is either a typo or an usual use of language. I've suggested new text for the sublabel. --- app/views/receive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/views/receive.js b/app/views/receive.js index 8fbccc0b..51c77896 100644 --- a/app/views/receive.js +++ b/app/views/receive.js @@ -20,7 +20,7 @@ import ShieldGrayImage from '../assets/images/shield_dark_gray.png'; import type { addressType } from '../redux/modules/receive'; import type { MapStateToProps, MapDispatchToProps } from '../containers/receive'; -const TRANSPARENT_ADDRESS_SUBLABEL = 'By using transaparent addresses you are forgiving any privacy properties to your transactions.'; +const TRANSPARENT_ADDRESS_SUBLABEL = 'Using a transparent address makes your transaction details public.'; const Row = styled(RowComponent)` margin-bottom: 10px; From 8c4416434e2891ec56d47a0e503e172a6918d80b Mon Sep 17 00:00:00 2001 From: George Lima Date: Fri, 31 May 2019 17:27:05 -0300 Subject: [PATCH 03/12] feat(github): add issues template --- .github/ISSUE_TEMPLATE/bug_report.md | 32 +++++++++++++++++++++++ .github/ISSUE_TEMPLATE/feature_request.md | 16 ++++++++++++ .github/ISSUE_TEMPLATE/question.md | 20 ++++++++++++++ 3 files changed, 68 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/bug_report.md create mode 100644 .github/ISSUE_TEMPLATE/feature_request.md create mode 100644 .github/ISSUE_TEMPLATE/question.md diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 00000000..e2622d09 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,32 @@ +--- +name: Bug Report 🐞 +about: Something isn't working as expected? Here is the right place to report. +--- + +## Description + +Describe the issue that you're seeing. + +### Steps to reproduce + +Clear steps describing how to reproduce the issue. This makes your issue _much_ easier to diagnose (seriously). + +### Expected result + +What should happen? + +### Actual result + +What happened. + +### Environment + +- What version of Zepio are you using? +- Which Operating System are you using (macOS/Linux/Windows)? What version? +- Are you using an external `zcashd` daemon or the one built inside Zepio? + +### Logs + +- `%APPDATA%/zepio/main-process-logs.txt` on Windows +- `$XDG_CONFIG_HOME/zepio/main-process-logs.txt` or `~/.config/zepio/main-process-logs.txt` on Linux +- `~/Library/Application Support/zepio/main-process-logs.txt` on macOS diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 00000000..fbaf1934 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,16 @@ +--- +name: Feature Request 💡 +about: Suggest a new idea for the project. +--- + +## Summary + +Brief explanation of the feature. + +### Basic example + +If the proposal involves a new or changed API, include a basic code example. Omit this section if it's not applicable. + +### Motivation + +Why are we doing this? What use cases does it support? What is the expected outcome? diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md new file mode 100644 index 00000000..2c836946 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/question.md @@ -0,0 +1,20 @@ +--- +name: Question 🤔 +about: Usage question or discussion about Gatsby. +--- + +## Summary + +## Relevant information + +### Environment (if relevant) + +- What version of Zepio are you using? +- Which Operating System are you using (macOS/Linux/Windows)? What version? +- Are you using an external `zcashd` daemon or the one built inside Zepio? + +### Logs (if relevant) + +- `%APPDATA%/zepio/main-process-logs.txt` on Windows +- `$XDG_CONFIG_HOME/zepio/main-process-logs.txt` or `~/.config/zepio/main-process-logs.txt` on Linux +- `~/Library/Application Support/zepio/main-process-logs.txt` on macOS From ec2609bb0fbfc5c2dfc9d9c0ec25320dff73ff2c Mon Sep 17 00:00:00 2001 From: Andre Neves Date: Sun, 2 Jun 2019 13:19:20 -0400 Subject: [PATCH 04/12] hotfix(responsive): refactoring UI on wallet summary to allow for small screens --- app/components/wallet-summary.js | 74 ++++++++++++++++++++------------ app/theme/index.js | 1 + app/theme/media-queries.js | 20 +++++++++ config/electron.js | 2 +- 4 files changed, 68 insertions(+), 29 deletions(-) create mode 100644 app/theme/media-queries.js diff --git a/app/components/wallet-summary.js b/app/components/wallet-summary.js index 1556d0c4..293aab3e 100644 --- a/app/components/wallet-summary.js +++ b/app/components/wallet-summary.js @@ -9,6 +9,8 @@ import { formatNumber } from '../utils/format-number'; import { getCoinName } from '../utils/get-coin-name'; import { DARK } from '../constants/themes'; +import { media } from '../theme'; + import ShieldDarkImage from '../assets/images/shield_dark.png'; import ShieldLightImage from '../assets/images/shield_light.png'; @@ -18,12 +20,17 @@ const OutsideWrapper = styled.div` const Wrapper = styled.div` display: flex; - flex-direction: row; + flex-direction: column; background-color: ${props => props.theme.colors.walletSummaryBg}; border: 1px solid ${props => props.theme.colors.walletSummaryBorder}; border-radius: ${props => props.theme.boxBorderRadius}; padding: 30px 30px; position: relative; + + ${media.main` + margin-top: 0; + flex-direction: row; + `} `; const OutsideLabel = styled(TextComponent)` @@ -86,6 +93,15 @@ const UnconfirmedValue = styled(MiddleLabel)` color: ${props => props.theme.colors.walletSummaryUnconfirmed}; `; +const DetailMainContainer = styled.div` + display: flex; + margin-top: 1rem; + + ${media.main` + margin-top: 0; + `} +`; + type Props = { total: number, shielded: number, @@ -120,33 +136,35 @@ export const Component = ({ size={theme.fontSize.medium * 2} /> - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + ); diff --git a/app/theme/index.js b/app/theme/index.js index da7221bf..1555ce01 100644 --- a/app/theme/index.js +++ b/app/theme/index.js @@ -3,3 +3,4 @@ export { appTheme } from './theme'; export { DoczWrapper } from './docz'; export { GlobalStyle } from './global'; +export { media } from './media-queries'; diff --git a/app/theme/media-queries.js b/app/theme/media-queries.js new file mode 100644 index 00000000..001bb25d --- /dev/null +++ b/app/theme/media-queries.js @@ -0,0 +1,20 @@ +// @flow + +import { css } from 'styled-components'; + +// Media Queries +export const sizes = { + main: 910, + // desktop: 1024, + // largeDesktop: 1280, +}; + +export const media = Object.keys(sizes).reduce((acc, label) => { + acc[label] = (...args: any) => css` + @media (min-width: ${sizes[label]}px) { + ${css(...args)} + } + `; + + return acc; +}, {}); diff --git a/config/electron.js b/config/electron.js index 576c7d97..5879ab28 100644 --- a/config/electron.js +++ b/config/electron.js @@ -57,7 +57,7 @@ const createWindow = () => { }); mainWindow = new BrowserWindow({ - minWidth: 700, + minWidth: 815, minHeight: 600, width: 1000, height: 660, From ad0147fef7c8b129b26a01cf8e349cee966d0bcc Mon Sep 17 00:00:00 2001 From: George Lima Date: Sun, 2 Jun 2019 21:18:48 -0300 Subject: [PATCH 05/12] feat(loading): add loading state - Receive - Send --- app/containers/receive.js | 7 +++++++ app/containers/send.js | 12 +++++++++++- app/redux/modules/receive.js | 22 +++++++++++++++++++++- app/redux/modules/send.js | 2 ++ app/views/receive.js | 8 +++++++- app/views/send.js | 20 ++++++++++++++++++-- 6 files changed, 66 insertions(+), 5 deletions(-) diff --git a/app/containers/receive.js b/app/containers/receive.js index d55c5199..4829fcc6 100644 --- a/app/containers/receive.js +++ b/app/containers/receive.js @@ -8,6 +8,7 @@ import { ReceiveView } from '../views/receive'; import { SAPLING } from '../constants/zcash-network'; import { + loadAddresses, loadAddressesSuccess, loadAddressesError, getNewAddressSuccess, @@ -25,11 +26,15 @@ import type { AppState } from '../types/app-state'; import type { Dispatch } from '../types/redux'; export type MapStateToProps = {| + isLoading: boolean, + isFirstLoad: boolean, addresses: { address: string, balance: number }[], |}; const mapStateToProps = ({ receive }: AppState): MapStateToProps => ({ addresses: receive.addresses, + isLoading: receive.isLoading, + isFirstLoad: receive.isFirstLoad, }); export type MapDispatchToProps = {| @@ -39,6 +44,8 @@ export type MapDispatchToProps = {| const mapDispatchToProps = (dispatch: Dispatch): MapDispatchToProps => ({ loadAddresses: async () => { + dispatch(loadAddresses()); + const [zAddressesErr, zAddresses] = await eres(rpc.z_listaddresses()); const [tAddressesErr, transparentAddresses] = await eres(rpc.getaddressesbyaccount('')); diff --git a/app/containers/send.js b/app/containers/send.js index 2b74e71c..caefeb11 100644 --- a/app/containers/send.js +++ b/app/containers/send.js @@ -28,7 +28,11 @@ import { saveShieldedTransaction } from '../../services/shielded-transactions'; import type { AppState } from '../types/app-state'; import type { Dispatch } from '../types/redux'; -import { loadAddressesSuccess, loadAddressesError } from '../redux/modules/receive'; +import { + loadAddresses, + loadAddressesSuccess, + loadAddressesError, +} from '../redux/modules/receive'; export type SendTransactionInput = { from: string, @@ -43,6 +47,8 @@ export type MapStateToProps = {| zecPrice: number, addresses: { address: string, balance: number }[], error: string | null, + isFirstLoad: boolean, + isLoading: boolean, isSending: boolean, operationId: string | null, isToAddressValid: boolean, @@ -54,6 +60,8 @@ const mapStateToProps = ({ sendStatus, receive, app }: AppState): MapStateToProp zecPrice: sendStatus.zecPrice, addresses: receive.addresses, error: sendStatus.error, + isFirstLoad: receive.isFirstLoad, + isLoading: receive.isLoading, isSending: sendStatus.isSending, operationId: sendStatus.operationId, isToAddressValid: sendStatus.isToAddressValid, @@ -160,6 +168,8 @@ const mapDispatchToProps = (dispatch: Dispatch): MapDispatchToProps => ({ return dispatch(validateAddressError()); }, loadAddresses: async () => { + dispatch(loadAddresses()); + const [zAddressesErr, zAddresses] = await eres(rpc.z_listaddresses()); const [tAddressesErr, transparentAddresses] = await eres(rpc.getaddressesbyaccount('')); diff --git a/app/redux/modules/receive.js b/app/redux/modules/receive.js index 650cc610..966f1d89 100644 --- a/app/redux/modules/receive.js +++ b/app/redux/modules/receive.js @@ -3,11 +3,17 @@ import type { Action } from '../../types/redux'; // Actions +export const LOAD_ADDRESSES = 'LOAD_ADDRESSES'; export const LOAD_ADDRESSES_SUCCESS = 'LOAD_ADDRESSES_SUCCESS'; export const LOAD_ADDRESSES_ERROR = 'LOAD_ADDRESSES_ERROR'; export const GET_NEW_ADDRESS_SUCCESS = 'GET_NEW_ADDRESS_SUCCESS'; export const GET_NEW_ADDRESS_ERROR = 'GET_NEW_ADDRESS_ERROR'; +export const loadAddresses = () => ({ + type: LOAD_ADDRESSES, + payload: {}, +}); + export const loadAddressesSuccess = ({ addresses, }: { @@ -41,6 +47,8 @@ export const getNewAddressError = ({ error }: { error: string }) => ({ export type addressType = 'transparent' | 'shielded'; export type State = { + isLoading: boolean, + isFirstLoad: boolean, addresses: { address: string, balance: number }[], error: string | null, }; @@ -48,23 +56,35 @@ export type State = { const initialState: State = { addresses: [], error: null, + isFirstLoad: true, + isLoading: false, }; // eslint-disable-next-line -export default (state: State = initialState, action: Action) => { +export default (state: State = initialState, action: Action): State => { switch (action.type) { + case LOAD_ADDRESSES: + return { + ...state, + isLoading: true, + }; case LOAD_ADDRESSES_SUCCESS: return { error: null, addresses: action.payload.addresses, + isLoading: false, + isFirstLoad: false, }; case LOAD_ADDRESSES_ERROR: return { error: action.payload.error, addresses: [], + isLoading: false, + isFirstLoad: false, }; case GET_NEW_ADDRESS_SUCCESS: return { + ...state, error: null, addresses: [...state.addresses, { address: action.payload.address, balance: 0 }], }; diff --git a/app/redux/modules/send.js b/app/redux/modules/send.js index b2923bcb..30828dc2 100644 --- a/app/redux/modules/send.js +++ b/app/redux/modules/send.js @@ -70,6 +70,7 @@ export const loadAddressBalanceError = ({ error }: { error: string }) => ({ }); export type State = { + isLoading: boolean, isSending: boolean, isToAddressValid: boolean, error: string | null, @@ -79,6 +80,7 @@ export type State = { }; const initialState: State = { + isLoading: true, isSending: false, error: null, operationId: null, diff --git a/app/views/receive.js b/app/views/receive.js index 51c77896..3df10f25 100644 --- a/app/views/receive.js +++ b/app/views/receive.js @@ -135,10 +135,16 @@ class Component extends PureComponent { }; render() { - const { addresses, theme } = this.props; + const { + addresses, theme, isLoading, isFirstLoad, + } = this.props; const { showAdditionalOptions } = this.state; const buttonText = `${showAdditionalOptions ? 'Hide' : 'Show'} Other Address Types`; + if (isFirstLoad && isLoading) { + return ; + } + const shieldedAddresses = addresses.filter(({ address }) => address.startsWith('z')); const transparentAddresses = addresses.filter(({ address }) => address.startsWith('t')); diff --git a/app/views/send.js b/app/views/send.js index 5c767505..0657723c 100644 --- a/app/views/send.js +++ b/app/views/send.js @@ -594,6 +594,12 @@ class Component extends PureComponent { ); }; + getLoadingIcon = () => { + const { theme } = this.props; + + return theme.mode === DARK ? LoadingIconDark : LoadingIconLight; + }; + renderModalContent = ({ valueSent, valueSentInUsd, @@ -607,11 +613,11 @@ class Component extends PureComponent { }) => { // eslint-disable-next-line react/prop-types const { - operationId, isSending, error, theme, + operationId, isSending, error, } = this.props; const { from, to } = this.state; - const loadingIcon = theme.mode === DARK ? LoadingIconDark : LoadingIconLight; + const loadingIcon = this.getLoadingIcon(); if (isSending) { return ( @@ -735,6 +741,8 @@ class Component extends PureComponent { balance, zecPrice, isSending, + isLoading, + isFirstLoad, error, operationId, theme, @@ -752,6 +760,14 @@ class Component extends PureComponent { showBalanceTooltip, } = this.state; + if (isFirstLoad && isLoading) { + return ( + + + + ); + } + const isEmpty = amount === ''; const fixedAmount = isEmpty || new BigNumber(amount).eq(0) ? 0 : this.getAmountWithFee(); From d36f8c2e878cf068dc716a8dc4acb8389837917b Mon Sep 17 00:00:00 2001 From: George Lima Date: Sun, 2 Jun 2019 21:22:08 -0300 Subject: [PATCH 06/12] type(flow): update flowtype badge --- public/flow-badge.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/flow-badge.svg b/public/flow-badge.svg index e8008e1b..037f59bd 100644 --- a/public/flow-badge.svg +++ b/public/flow-badge.svg @@ -1 +1 @@ -flowflowfailingfailing \ No newline at end of file +flowflowpassingpassing \ No newline at end of file From 4e39ea5334117dbc06974ffdc38bc3cca87a5488 Mon Sep 17 00:00:00 2001 From: George Lima Date: Tue, 4 Jun 2019 21:28:06 -0300 Subject: [PATCH 07/12] feature(redux): add fetchStateHandler middleware --- app/redux/create.js | 8 +++++++- app/redux/fetchStateHandler.js | 31 +++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) create mode 100644 app/redux/fetchStateHandler.js diff --git a/app/redux/create.js b/app/redux/create.js index fe65d9e7..224daa41 100644 --- a/app/redux/create.js +++ b/app/redux/create.js @@ -8,6 +8,7 @@ import type { RouterHistory } from 'react-router-dom'; import { createRootReducer } from './modules/reducer'; import { errorHandler } from './errorHandler'; +import { fetchStateHandler } from './fetchStateHandler'; export const history: RouterHistory = createHashHistory(); @@ -16,7 +17,12 @@ const shouldEnableDevTools = (process.env.NODE_ENV !== 'production' || process.e export const configureStore = (initialState: Object) => { // $FlowFixMe - const middleware = applyMiddleware(thunk, routerMiddleware(history), errorHandler); + const middleware = applyMiddleware( + thunk, + routerMiddleware(history), + errorHandler, + fetchStateHandler, + ); const enhancer = compose( middleware, diff --git a/app/redux/fetchStateHandler.js b/app/redux/fetchStateHandler.js new file mode 100644 index 00000000..6e9c0696 --- /dev/null +++ b/app/redux/fetchStateHandler.js @@ -0,0 +1,31 @@ +// @flow +import { LOAD_ADDRESSES } from './modules/receive'; +import { LOAD_TRANSACTIONS } from './modules/transactions'; +import { LOAD_WALLET_SUMMARY } from './modules/wallet'; + +import { FETCH_STATE } from '../constants/fetch-states'; + +import type { Middleware } from '../types/redux'; + +const calls = new Set(); + +export const fetchStateHandler: Middleware = () => next => (action) => { + if ( + action.type === LOAD_ADDRESSES + || action.type === LOAD_TRANSACTIONS + || action.type === LOAD_WALLET_SUMMARY + ) { + if (calls.has(action.type)) { + return next({ + ...action, + fetchState: FETCH_STATE.REFETCHING, + }); + } + + calls.add(action.type); + + return next({ ...action, fetchState: FETCH_STATE.INITIALIZING }); + } + + return next(action); +}; From 8e0dd4ae392d285324b3942bad5896ff4fc669ac Mon Sep 17 00:00:00 2001 From: George Lima Date: Tue, 4 Jun 2019 21:29:21 -0300 Subject: [PATCH 08/12] feat(loader): add loader component --- app/components/loader.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/components/loader.js diff --git a/app/components/loader.js b/app/components/loader.js new file mode 100644 index 00000000..7ab6468b --- /dev/null +++ b/app/components/loader.js @@ -0,0 +1,20 @@ +// @flow +import React from 'react'; +import styled from 'styled-components'; + +import { TextComponent } from './text'; + +const Wrapper = styled.div` + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + text-align: center; +`; + +export const LoaderComponent = () => ( + + + +); From f1732f8101aa88cd2a4710a058061e88530327c1 Mon Sep 17 00:00:00 2001 From: George Lima Date: Tue, 4 Jun 2019 21:31:15 -0300 Subject: [PATCH 09/12] feat(status-pill): add StatusPill refetching status --- __tests__/components/status-pill.test.js | 3 ++ app/components/status-pill.js | 50 +++++++++++++++++------- app/containers/status-pill.js | 7 +++- 3 files changed, 45 insertions(+), 15 deletions(-) diff --git a/__tests__/components/status-pill.test.js b/__tests__/components/status-pill.test.js index ea690e76..77252c8c 100644 --- a/__tests__/components/status-pill.test.js +++ b/__tests__/components/status-pill.test.js @@ -18,6 +18,7 @@ describe('', () => { getBlockchainStatus={() => Promise.resolve()} nodeSyncProgress={56.0} nodeSyncType='syncing' + isRefetching={false} /> , ); @@ -32,6 +33,7 @@ describe('', () => { getBlockchainStatus={() => Promise.resolve()} nodeSyncProgress={100.0} nodeSyncType='ready' + isRefetching={false} /> , ); @@ -46,6 +48,7 @@ describe('', () => { getBlockchainStatus={() => Promise.resolve()} nodeSyncProgress={0.0} nodeSyncType='error' + isRefetching={false} /> , ); diff --git a/app/components/status-pill.js b/app/components/status-pill.js index 6c25e96b..9008c600 100644 --- a/app/components/status-pill.js +++ b/app/components/status-pill.js @@ -27,6 +27,14 @@ const rotate = keyframes` `; const Wrapper = styled.div` + display: flex; + flex-direction: row; + align-items: flex-end; + justify-content: center; + height: 100%; +`; + +const StatusWrapper = styled.div` align-items: center; display: flex; background: ${props => props.theme.colors.statusPillBg}; @@ -90,6 +98,15 @@ const TooltipText = styled(TextComponent)` font-weight: 700; `; +const RefetchingLabel = styled.p` + color: ${props => props.theme.colors.sidebarItem}; + font-size: 10px; + letter-spacing: 0.5px; + text-transform: uppercase; + font-family: ${props => props.theme.fontFamily}; + margin-right: 10px; +`; + type Props = { theme: AppTheme, } & MapStateToProps & @@ -219,26 +236,31 @@ class Component extends PureComponent { render() { const icon = this.getIcon(); - const { nodeSyncType, nodeSyncProgress } = this.props; + const { nodeSyncType, nodeSyncProgress, isRefetching } = this.props; const { showTooltip } = this.state; const percent = nodeSyncType && nodeSyncType === NODE_SYNC_TYPES.SYNCING ? `(${nodeSyncProgress.toFixed(2)}%)` : ''; return ( - // eslint-disable-next-line - this.setState({ showTooltip: true })} - onMouseOut={() => this.setState({ showTooltip: false })} - id='status-pill' - > - {showTooltip && ( - - - - )} - {icon && } - + + {isRefetching && Refetching...} + { + // eslint-disable-next-line + this.setState({ showTooltip: true })} + onMouseOut={() => this.setState({ showTooltip: false })} + id='status-pill' + > + {showTooltip && ( + + + + )} + {icon && } + + + } ); } diff --git a/app/containers/status-pill.js b/app/containers/status-pill.js index ddef1a13..a48d8fc5 100644 --- a/app/containers/status-pill.js +++ b/app/containers/status-pill.js @@ -8,6 +8,7 @@ import { updateNodeSyncStatus } from '../redux/modules/app'; import { StatusPill } from '../components/status-pill'; import rpc from '../../services/api'; import { NODE_SYNC_TYPES } from '../constants/node-sync-types'; +import { FETCH_STATE } from '../constants/fetch-states'; import type { Dispatch } from '../types/redux'; import type { AppState } from '../types/app-state'; @@ -15,11 +16,15 @@ import type { AppState } from '../types/app-state'; export type MapStateToProps = {| nodeSyncProgress: number, nodeSyncType: 'ready' | 'syncing' | 'error', + isRefetching: boolean, |}; -const mapStateToProps = ({ app }: AppState): MapStateToProps => ({ +const mapStateToProps = ({ app, walletSummary, receive }: AppState): MapStateToProps => ({ nodeSyncProgress: app.nodeSyncProgress, nodeSyncType: app.nodeSyncType, + isRefetching: + walletSummary.fetchState === FETCH_STATE.REFETCHING + || receive.fetchState === FETCH_STATE.REFETCHING, }); export type MapDispatchToProps = {| From b505974b3915e343fe8faacda2a91b677612e623 Mon Sep 17 00:00:00 2001 From: George Lima Date: Tue, 4 Jun 2019 21:32:37 -0300 Subject: [PATCH 10/12] feat(fetch-state): add FETCH_STATES --- app/constants/fetch-states.js | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 app/constants/fetch-states.js diff --git a/app/constants/fetch-states.js b/app/constants/fetch-states.js new file mode 100644 index 00000000..52805663 --- /dev/null +++ b/app/constants/fetch-states.js @@ -0,0 +1,7 @@ +// @flow +export const FETCH_STATE = { + INITIALIZING: 'INITIALIZING', + REFETCHING: 'REFETCHING', + SUCCESS: 'SUCCESS', + ERROR: 'ERROR', +}; From 28a0a31feecf8e98bfd57ead23fa9f5b77778061 Mon Sep 17 00:00:00 2001 From: George Lima Date: Tue, 4 Jun 2019 21:35:02 -0300 Subject: [PATCH 11/12] feat(loading-state): add fetchState in screens --- app/containers/dashboard.js | 28 +++++++++++++++++++++++----- app/containers/receive.js | 8 +++----- app/containers/send.js | 14 ++++---------- app/containers/transactions.js | 2 +- app/redux/modules/app.js | 8 +++++--- app/redux/modules/receive.js | 17 +++++++---------- app/redux/modules/transactions.js | 15 +++++++++------ app/redux/modules/wallet.js | 20 ++++++++++++++------ app/types/redux.js | 4 +++- app/views/dashboard.js | 29 ++++++++++------------------- app/views/receive.js | 10 +++++----- app/views/send.js | 17 ++++++----------- 12 files changed, 90 insertions(+), 82 deletions(-) diff --git a/app/containers/dashboard.js b/app/containers/dashboard.js index f18d9847..9e4d04f1 100644 --- a/app/containers/dashboard.js +++ b/app/containers/dashboard.js @@ -21,24 +21,42 @@ import { loadWalletSummarySuccess, loadWalletSummaryError, } from '../redux/modules/wallet'; +import type { TransactionsList } from '../redux/modules/transactions'; import type { AppState } from '../types/app-state'; -import type { Dispatch } from '../types/redux'; - -const mapStateToProps = ({ walletSummary, app }: AppState) => ({ +import type { Dispatch, FetchState } from '../types/redux'; + +export type MapStateToProps = {| + total: number, + shielded: number, + transparent: number, + unconfirmed: number, + error: null | string, + fetchState: FetchState, + zecPrice: number, + addresses: string[], + transactions: TransactionsList, + isDaemonReady: boolean, +|}; + +const mapStateToProps: AppState => MapStateToProps = ({ walletSummary, app }) => ({ total: walletSummary.total, shielded: walletSummary.shielded, transparent: walletSummary.transparent, unconfirmed: walletSummary.unconfirmed, error: walletSummary.error, - isLoading: walletSummary.isLoading, + fetchState: walletSummary.fetchState, zecPrice: walletSummary.zecPrice, addresses: walletSummary.addresses, transactions: walletSummary.transactions, isDaemonReady: app.nodeSyncType === NODE_SYNC_TYPES.READY, }); -const mapDispatchToProps = (dispatch: Dispatch) => ({ +export type MapDispatchToProps = {| + getSummary: () => Promise, +|}; + +const mapDispatchToProps: (dispatch: Dispatch) => MapDispatchToProps = (dispatch: Dispatch) => ({ getSummary: async () => { dispatch(loadWalletSummary()); diff --git a/app/containers/receive.js b/app/containers/receive.js index 4829fcc6..36661bc2 100644 --- a/app/containers/receive.js +++ b/app/containers/receive.js @@ -23,18 +23,16 @@ import rpc from '../../services/api'; import electronStore from '../../config/electron-store'; import type { AppState } from '../types/app-state'; -import type { Dispatch } from '../types/redux'; +import type { Dispatch, FetchState } from '../types/redux'; export type MapStateToProps = {| - isLoading: boolean, - isFirstLoad: boolean, + fetchState: FetchState, addresses: { address: string, balance: number }[], |}; const mapStateToProps = ({ receive }: AppState): MapStateToProps => ({ addresses: receive.addresses, - isLoading: receive.isLoading, - isFirstLoad: receive.isFirstLoad, + fetchState: receive.fetchState, }); export type MapDispatchToProps = {| diff --git a/app/containers/send.js b/app/containers/send.js index caefeb11..b1db0b28 100644 --- a/app/containers/send.js +++ b/app/containers/send.js @@ -26,13 +26,9 @@ import { getLatestAddressKey } from '../utils/get-latest-address-key'; import { saveShieldedTransaction } from '../../services/shielded-transactions'; import type { AppState } from '../types/app-state'; -import type { Dispatch } from '../types/redux'; +import type { Dispatch, FetchState } from '../types/redux'; -import { - loadAddresses, - loadAddressesSuccess, - loadAddressesError, -} from '../redux/modules/receive'; +import { loadAddresses, loadAddressesSuccess, loadAddressesError } from '../redux/modules/receive'; export type SendTransactionInput = { from: string, @@ -47,8 +43,7 @@ export type MapStateToProps = {| zecPrice: number, addresses: { address: string, balance: number }[], error: string | null, - isFirstLoad: boolean, - isLoading: boolean, + fetchState: FetchState, isSending: boolean, operationId: string | null, isToAddressValid: boolean, @@ -60,8 +55,7 @@ const mapStateToProps = ({ sendStatus, receive, app }: AppState): MapStateToProp zecPrice: sendStatus.zecPrice, addresses: receive.addresses, error: sendStatus.error, - isFirstLoad: receive.isFirstLoad, - isLoading: receive.isLoading, + fetchState: receive.fetchState, isSending: sendStatus.isSending, operationId: sendStatus.operationId, isToAddressValid: sendStatus.isToAddressValid, diff --git a/app/containers/transactions.js b/app/containers/transactions.js index de2e1087..8dc876d1 100644 --- a/app/containers/transactions.js +++ b/app/containers/transactions.js @@ -24,7 +24,7 @@ import type { Transaction } from '../components/transaction-item'; const mapStateToProps = ({ transactions }: AppState) => ({ transactions: transactions.list, - isLoading: transactions.isLoading, + fetchState: transactions.fetchState, error: transactions.error, zecPrice: transactions.zecPrice, hasNextPage: transactions.hasNextPage, diff --git a/app/redux/modules/app.js b/app/redux/modules/app.js index c3124de8..1df0b839 100644 --- a/app/redux/modules/app.js +++ b/app/redux/modules/app.js @@ -14,6 +14,7 @@ export type State = {| nodeSyncType: 'ready' | 'syncing' | 'error', zcashNetwork: string, embeddedDaemon: boolean, + isRefetching: boolean, |}; // Actions @@ -54,15 +55,16 @@ const initialState: State = { nodeSyncType: NODE_SYNC_TYPES.SYNCING, zcashNetwork: electronStore.get(ZCASH_NETWORK), embeddedDaemon: electronStore.get(EMBEDDED_DAEMON), + isRefetching: false, }; // eslint-disable-next-line -export default (state: State = initialState, action: Action) => { +export default (state: State = initialState, action: Action): State => { switch (action.type) { case SHOW_ERROR_MODAL: - return { isErrorModalVisible: true, error: action.payload.error }; + return { ...state, isErrorModalVisible: true, error: action.payload.error }; case HIDE_ERROR_MODAL: - return { isErrorModalVisible: false, error: null }; + return { ...state, isErrorModalVisible: false, error: null }; case UPDATE_NODE_SYNC_STATUS: return { ...state, diff --git a/app/redux/modules/receive.js b/app/redux/modules/receive.js index 966f1d89..5841e32e 100644 --- a/app/redux/modules/receive.js +++ b/app/redux/modules/receive.js @@ -1,6 +1,7 @@ // @flow +import { FETCH_STATE } from '../../constants/fetch-states'; -import type { Action } from '../../types/redux'; +import type { Action, FetchState } from '../../types/redux'; // Actions export const LOAD_ADDRESSES = 'LOAD_ADDRESSES'; @@ -47,17 +48,15 @@ export const getNewAddressError = ({ error }: { error: string }) => ({ export type addressType = 'transparent' | 'shielded'; export type State = { - isLoading: boolean, - isFirstLoad: boolean, addresses: { address: string, balance: number }[], error: string | null, + fetchState: FetchState, }; const initialState: State = { addresses: [], error: null, - isFirstLoad: true, - isLoading: false, + fetchState: FETCH_STATE.INITIALIZING, }; // eslint-disable-next-line @@ -66,21 +65,19 @@ export default (state: State = initialState, action: Action): State => { case LOAD_ADDRESSES: return { ...state, - isLoading: true, + fetchState: action.fetchState, }; case LOAD_ADDRESSES_SUCCESS: return { error: null, addresses: action.payload.addresses, - isLoading: false, - isFirstLoad: false, + fetchState: FETCH_STATE.SUCCESS, }; case LOAD_ADDRESSES_ERROR: return { error: action.payload.error, addresses: [], - isLoading: false, - isFirstLoad: false, + fetchState: FETCH_STATE.ERROR, }; case GET_NEW_ADDRESS_SUCCESS: return { diff --git a/app/redux/modules/transactions.js b/app/redux/modules/transactions.js index 6d65db22..0ea61d68 100644 --- a/app/redux/modules/transactions.js +++ b/app/redux/modules/transactions.js @@ -1,7 +1,9 @@ // @flow import uniqBy from 'lodash.uniqby'; -import type { Action } from '../../types/redux'; +import { FETCH_STATE } from '../../constants/fetch-states'; + +import type { Action, FetchState } from '../../types/redux'; import type { Transaction } from '../../components/transaction-item'; // Actions @@ -45,19 +47,19 @@ export const resetTransactionsList = () => ({ }); export type State = { - isLoading: boolean, error: string | null, list: Transaction[], zecPrice: number, hasNextPage: boolean, + fetchState: FetchState, }; const initialState = { zecPrice: 0, list: [], error: null, - isLoading: false, hasNextPage: true, + fetchState: FETCH_STATE.INITIALIZING, }; // eslint-disable-next-line @@ -67,26 +69,27 @@ export default (state: State = initialState, action: Action) => { return { ...state, error: null, - isLoading: true, + fetchState: action.fetchState, }; case LOAD_TRANSACTIONS_SUCCESS: return { ...state, ...action.payload, list: uniqBy(state.list.concat(action.payload.list), tr => tr.transactionId + tr.type), - isLoading: false, + fetchState: FETCH_STATE.SUCCESS, error: null, }; case LOAD_TRANSACTIONS_ERROR: return { ...state, - isLoading: false, + fetchState: FETCH_STATE.ERROR, error: action.payload.error, }; case RESET_TRANSACTIONS_LIST: return { ...state, isLoading: false, + isRefreshing: false, error: null, list: [], }; diff --git a/app/redux/modules/wallet.js b/app/redux/modules/wallet.js index 37b98605..d5a37a27 100644 --- a/app/redux/modules/wallet.js +++ b/app/redux/modules/wallet.js @@ -1,6 +1,7 @@ // @flow +import { FETCH_STATE } from '../../constants/fetch-states'; -import type { Action } from '../../types/redux'; +import type { Action, FetchState } from '../../types/redux'; import type { TransactionsList } from './transactions'; // Actions @@ -54,10 +55,10 @@ export type State = { transparent: number, unconfirmed: number, error: string | null, - isLoading: boolean, zecPrice: number, addresses: string[], transactions: TransactionsList, + fetchState: FetchState, }; const initialState = { @@ -66,26 +67,33 @@ const initialState = { transparent: 0, unconfirmed: 0, error: null, - isLoading: false, zecPrice: 0, addresses: [], transactions: [], + fetchState: FETCH_STATE.INITIALIZING, }; // eslint-disable-next-line export default (state: State = initialState, action: Action) => { switch (action.type) { case LOAD_WALLET_SUMMARY: - return { ...state, isLoading: true }; + return { + ...state, + fetchState: action.fetchState, + }; case LOAD_WALLET_SUMMARY_SUCCESS: return { ...state, ...action.payload, - isLoading: false, + fetchState: 'SUCCESS', error: null, }; case LOAD_WALLET_SUMMARY_ERROR: - return { ...state, isLoading: false, error: action.payload.error }; + return { + ...state, + fetchState: 'ERROR', + error: action.payload.error, + }; default: return state; } diff --git a/app/types/redux.js b/app/types/redux.js index 831cbf3e..673f7be4 100644 --- a/app/types/redux.js +++ b/app/types/redux.js @@ -2,7 +2,9 @@ import type { AppState } from './app-state'; -export type Action = { type: string, payload: Object }; +export type FetchState = 'INITIALIZING' | 'REFETCHING' | 'SUCCESS' | 'ERROR'; + +export type Action = { type: string, payload: Object, fetchState?: FetchState }; export type GetState = () => AppState; export type Dispatch = (action: Action) => void; export type Middleware = ({ dispatch: Dispatch, getState: GetState }) => ( diff --git a/app/views/dashboard.js b/app/views/dashboard.js index aa6934af..40f626ae 100644 --- a/app/views/dashboard.js +++ b/app/views/dashboard.js @@ -1,6 +1,6 @@ // @flow -import React, { PureComponent, Fragment } from 'react'; +import React, { PureComponent } from 'react'; import styled from 'styled-components'; import electron from 'electron'; // eslint-disable-line import/no-extraneous-dependencies @@ -10,10 +10,12 @@ import { TextComponent } from '../components/text'; import { EmptyTransactionsComponent } from '../components/empty-transactions'; import { ConfirmDialogComponent } from '../components/confirm-dialog'; import { ColumnComponent } from '../components/column'; +import { LoaderComponent } from '../components/loader'; import store from '../../config/electron-store'; +import { FETCH_STATE } from '../constants/fetch-states'; -import type { TransactionsList } from '../redux/modules/transactions'; +import type { MapDispatchToProps, MapStateToProps } from '../containers/dashboard'; import zepioLogo from '../assets/images/zcash-icon.png'; @@ -57,18 +59,7 @@ const AdditionalText = styled(TextComponent)` font-size: 10px; `; -type Props = { - getSummary: () => void, - total: number, - shielded: number, - transparent: number, - unconfirmed: number, - error: string | null, - zecPrice: number, - addresses: string[], - isDaemonReady: boolean, - transactions: TransactionsList, -}; +type Props = MapDispatchToProps & MapStateToProps; const UPDATE_INTERVAL = 10000; const DISPLAY_WELCOME_MODAL = 'DISPLAY_WELCOME_MODAL'; @@ -94,7 +85,6 @@ export class DashboardView extends PureComponent { render() { const { - error, total, shielded, transparent, @@ -102,14 +92,15 @@ export class DashboardView extends PureComponent { zecPrice, addresses, transactions, + fetchState, } = this.props; - if (error) { - return ; + if (fetchState === FETCH_STATE.INITIALIZING) { + return ; } return ( - + <> { )} )} - + ); } } diff --git a/app/views/receive.js b/app/views/receive.js index 3df10f25..6f85de63 100644 --- a/app/views/receive.js +++ b/app/views/receive.js @@ -5,11 +5,13 @@ import styled, { withTheme } from 'styled-components'; import { Transition, animated } from 'react-spring'; import { DARK } from '../constants/themes'; +import { FETCH_STATE } from '../constants/fetch-states'; import { InputLabelComponent } from '../components/input-label'; import { RowComponent } from '../components/row'; import { TextComponent } from '../components/text'; import { WalletAddress } from '../components/wallet-address'; +import { LoaderComponent } from '../components/loader'; import MenuIconDark from '../assets/images/menu_icon_dark.svg'; import MenuIconLight from '../assets/images/menu_icon_light.svg'; @@ -135,14 +137,12 @@ class Component extends PureComponent { }; render() { - const { - addresses, theme, isLoading, isFirstLoad, - } = this.props; + const { addresses, theme, fetchState } = this.props; const { showAdditionalOptions } = this.state; const buttonText = `${showAdditionalOptions ? 'Hide' : 'Show'} Other Address Types`; - if (isFirstLoad && isLoading) { - return ; + if (fetchState === FETCH_STATE.INITIALIZING) { + return ; } const shieldedAddresses = addresses.filter(({ address }) => address.startsWith('z')); diff --git a/app/views/send.js b/app/views/send.js index 0657723c..b1760ea1 100644 --- a/app/views/send.js +++ b/app/views/send.js @@ -9,6 +9,7 @@ import { type Match } from 'react-router-dom'; import { FEES } from '../constants/fees'; import { DARK } from '../constants/themes'; import { NODE_SYNC_TYPES } from '../constants/node-sync-types'; +import { FETCH_STATE } from '../constants/fetch-states'; import { InputLabelComponent } from '../components/input-label'; import { InputComponent } from '../components/input'; @@ -19,6 +20,7 @@ import { ColumnComponent } from '../components/column'; import { Divider } from '../components/divider'; import { Button } from '../components/button'; import { ConfirmDialogComponent } from '../components/confirm-dialog'; +import { LoaderComponent } from '../components/loader'; import { formatNumber } from '../utils/format-number'; import { ascii2hex } from '../utils/ascii-to-hexadecimal'; @@ -612,9 +614,7 @@ class Component extends PureComponent { /* eslint-enable react/no-unused-prop-types */ }) => { // eslint-disable-next-line react/prop-types - const { - operationId, isSending, error, - } = this.props; + const { operationId, isSending, error } = this.props; const { from, to } = this.state; const loadingIcon = this.getLoadingIcon(); @@ -741,12 +741,11 @@ class Component extends PureComponent { balance, zecPrice, isSending, - isLoading, - isFirstLoad, error, operationId, theme, nodeSyncType, + fetchState, } = this.props; const { showFee, @@ -760,12 +759,8 @@ class Component extends PureComponent { showBalanceTooltip, } = this.state; - if (isFirstLoad && isLoading) { - return ( - - - - ); + if (fetchState === FETCH_STATE.INITIALIZING) { + return ; } const isEmpty = amount === ''; From 1eecdc4800bbad83a07252ade25b80282566fc36 Mon Sep 17 00:00:00 2001 From: Andre Neves Date: Thu, 6 Jun 2019 21:15:32 -0400 Subject: [PATCH 12/12] chore(version): bumping to v0.7.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66160dbd..e5749e49 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "zepio", "productName": "Zepio", - "version": "0.7.2", + "version": "0.7.3", "description": "Zepio | Cross-platform sapling-enabled full-node Zcash wallet", "main": "config/main.js", "homepage": "https://zepiowallet.com",