From 1dfca2aba14d370540e9b9aab6067237aa535510 Mon Sep 17 00:00:00 2001 From: Paul Ccari Date: Thu, 12 Aug 2021 13:06:07 -0500 Subject: [PATCH 1/4] fix conditional render in sidebar items --- .../app/stores/stateless/sidebarCategories.js | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/packages/yoroi-extension/app/stores/stateless/sidebarCategories.js b/packages/yoroi-extension/app/stores/stateless/sidebarCategories.js index 84aaf9357f..534b9d4890 100644 --- a/packages/yoroi-extension/app/stores/stateless/sidebarCategories.js +++ b/packages/yoroi-extension/app/stores/stateless/sidebarCategories.js @@ -116,65 +116,62 @@ export const allCategoriesRevamp: Array = [ route: ROUTES.MY_WALLETS, icon: walletIcon, label: globalMessages.walletLabel, - isVisible: request => - request.hasAnyWallets && - request.selected == null && - matchRoute(ROUTES.WALLETS.ADD, request.currentRoute) === false, + isVisible: _request => true, }, { className: 'staking', route: '/staking', icon: stakingIcon, label: globalMessages.sidebarStaking, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'assets', route: '/assets', icon: assetsIcon, label: globalMessages.sidebarAssets, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'voting', route: '/voting', icon: votingIcon, label: globalMessages.sidebarVoting, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'swap', route: '/swap', icon: swapIcon, label: globalMessages.sidebarSwap, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'settings', route: '/settings', icon: settingIcon, label: globalMessages.sidebarSettings, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'faq', route: 'https://yoroi-wallet.com/faq', icon: faqIcon, label: globalMessages.sidebarFaq, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'new-updates', route: '/new-updates', icon: newUpdatesIcon, label: globalMessages.sidebarNewUpdates, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, { className: 'feedback', route: '/feedback', icon: feedbackIcon, label: globalMessages.sidebarFeedback, - isVisible: request => request.hasAnyWallets, + isVisible: _request => true, }, ]; From 60bb84ea15bd15f7378b916f39fd574ab31c6edb Mon Sep 17 00:00:00 2001 From: Paul Ccari Date: Thu, 12 Aug 2021 18:34:42 -0500 Subject: [PATCH 2/4] add layout context, provider and hoc --- packages/yoroi-extension/app/App.js | 30 ++++----- .../app/themes/context/layout.js | 62 +++++++++++++++++++ packages/yoroi-extension/app/themes/index.js | 4 ++ 3 files changed, 82 insertions(+), 14 deletions(-) create mode 100644 packages/yoroi-extension/app/themes/context/layout.js diff --git a/packages/yoroi-extension/app/App.js b/packages/yoroi-extension/app/App.js index db6d0159d0..384a271dc1 100644 --- a/packages/yoroi-extension/app/App.js +++ b/packages/yoroi-extension/app/App.js @@ -33,6 +33,7 @@ import CrashPage from './containers/CrashPage'; import { Logger, } from './utils/logging'; import { SimpleSkins } from 'react-polymorph/lib/skins/simple'; import { SimpleDefaults } from 'react-polymorph/lib/themes/simple'; +import { LayoutProvider } from './themes/context/layout'; // https://github.com/yahoo/react-intl/wiki#loading-locale-data addLocaleData([ @@ -105,20 +106,21 @@ class App extends Component { return (
- - - {/* Automatically pass a theme prop to all components in this subtree. */} - - - {this.getContent()} - - + + + {/* Automatically pass a theme prop to all components in this subtree. */} + + + {this.getContent()} + + +
); } diff --git a/packages/yoroi-extension/app/themes/context/layout.js b/packages/yoroi-extension/app/themes/context/layout.js new file mode 100644 index 0000000000..db4269d229 --- /dev/null +++ b/packages/yoroi-extension/app/themes/context/layout.js @@ -0,0 +1,62 @@ +// @flow +import React from 'react'; +import type { Node } from 'react'; +import { THEMES, THEMES_REVAMP } from '..'; + +type layoutState = {| + selected: string, + [key: 'CLASSIC' | 'REVAMP']: {| + themes: Object, + |}, +|}; +const initialState: layoutState = { + selected: 'CLASSIC', + CLASSIC: { + themes: THEMES, + }, + REVAMP: { + themes: THEMES_REVAMP, + }, +}; + +const LayoutContext = React.createContext(); + +function layoutReducer(state, action) { + switch (action.type) { + case 'CHANGE_LAYOUT': { + return { ...state, selected: state.selected === 'CLASSIC' ? 'REVAMP' : 'CLASSIC' }; + } + default: + return state; + } +} + +const LayoutProvider = (props: Object): Node => { + const [state, dispatch] = React.useReducer(layoutReducer, initialState); + + return ( + dispatch({ type: 'CHANGE_LAYOUT' }), + }} + {...props} + /> + ); +}; + +function useLayout(): layoutState { + const context = React.useContext(LayoutContext); + if (!context) { + throw new Error('useLayout must be used within a LayoutProvider'); + } + return context; +} + +const withLayout = (WrappedComponent: Function): Function => props => { + const layoutProps = useLayout(); + return ; +}; + +export { LayoutProvider, useLayout, withLayout }; diff --git a/packages/yoroi-extension/app/themes/index.js b/packages/yoroi-extension/app/themes/index.js index 4ac52ea15f..f2685d626c 100644 --- a/packages/yoroi-extension/app/themes/index.js +++ b/packages/yoroi-extension/app/themes/index.js @@ -4,8 +4,12 @@ export const THEMES = Object.freeze({ YOROI_CLASSIC: 'YoroiClassic', YOROI_MODERN: 'YoroiModern', }); +export const THEMES_REVAMP = Object.freeze({ + YOROI_REVAMP: 'YoroiRevamp', +}); export type Theme = $Values; +export type ThemeRevamp = $Values; // Refer: https://github.com/Emurgo/yoroi-frontend/pull/497 From 12bafa1d82f8d5003cb0bf5f777f24ae5cf4da99 Mon Sep 17 00:00:00 2001 From: Paul Ccari Date: Thu, 12 Aug 2021 18:37:52 -0500 Subject: [PATCH 3/4] fix: add withLayout in sidebar --- .../app/containers/SidebarContainer.js | 40 +++++++++++-------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/packages/yoroi-extension/app/containers/SidebarContainer.js b/packages/yoroi-extension/app/containers/SidebarContainer.js index aa52996189..941ffb1d36 100644 --- a/packages/yoroi-extension/app/containers/SidebarContainer.js +++ b/packages/yoroi-extension/app/containers/SidebarContainer.js @@ -1,5 +1,5 @@ // @flow -import type { Node } from 'react'; +import type { ComponentType, Node } from 'react'; import React, { Component } from 'react'; import { observer } from 'mobx-react'; import { computed } from 'mobx'; @@ -8,22 +8,29 @@ import type { InjectedOrGenerated } from '../types/injectedPropsType'; import { allCategories, allCategoriesRevamp } from '../stores/stateless/sidebarCategories'; import { PublicDeriver } from '../api/ada/lib/storage/models/PublicDeriver'; import SidebarRevamp from '../components/topbar/SidebarRevamp'; +import { withLayout } from '../themes/context/layout'; export type GeneratedData = typeof SidebarContainer.prototype.generated; -@observer -export default class SidebarContainer extends Component> { +type Props = {| + ...InjectedOrGenerated, +|}; +type InjectedProps = {| + +isRevampLayout: boolean, +|}; +type AllProps = {| ...Props, ...InjectedProps |}; +@observer +class SidebarContainer extends Component { toggleSidebar: void => Promise = async () => { await this.generated.actions.profile.toggleSidebar.trigger(); - } + }; render(): Node { const { stores } = this.generated; const { profile } = stores; - // TODO: Remove hardcoded variable - const isRevampTheme = false; - return isRevampTheme ? ( + + return this.props.isRevampLayout ? ( { this.generated.actions.router.goToRoute.trigger({ @@ -68,17 +75,17 @@ export default class SidebarContainer extends Component Promise - |} + trigger: (params: void) => Promise, + |}, |}, router: {| goToRoute: {| trigger: (params: {| publicDeriver?: null | PublicDeriver<>, params?: ?any, - route: string - |}) => void - |} + route: string, + |}) => void, + |}, |}, |}, stores: {| @@ -86,10 +93,10 @@ export default class SidebarContainer extends Component - |} - |} - |} { + selected: null | PublicDeriver<>, + |}, + |}, + |} { if (this.props.generated !== undefined) { return this.props.generated; } @@ -121,3 +128,4 @@ export default class SidebarContainer extends Component); From d42caf71e0fe1c8eb61d03497e1ae136642b0004 Mon Sep 17 00:00:00 2001 From: Paul Ccari Date: Fri, 20 Aug 2021 00:15:21 -0500 Subject: [PATCH 4/4] fix: render dynamic component acording to layout selected --- .../app/containers/SidebarContainer.js | 27 ++++--- .../app/containers/SidebarRevampContainer.js | 81 ------------------- .../app/themes/context/layout.js | 19 +++-- 3 files changed, 32 insertions(+), 95 deletions(-) delete mode 100644 packages/yoroi-extension/app/containers/SidebarRevampContainer.js diff --git a/packages/yoroi-extension/app/containers/SidebarContainer.js b/packages/yoroi-extension/app/containers/SidebarContainer.js index 941ffb1d36..fa9fc614ed 100644 --- a/packages/yoroi-extension/app/containers/SidebarContainer.js +++ b/packages/yoroi-extension/app/containers/SidebarContainer.js @@ -9,6 +9,7 @@ import { allCategories, allCategoriesRevamp } from '../stores/stateless/sidebarC import { PublicDeriver } from '../api/ada/lib/storage/models/PublicDeriver'; import SidebarRevamp from '../components/topbar/SidebarRevamp'; import { withLayout } from '../themes/context/layout'; +import type { LayoutComponentMap } from '../themes/context/layout'; export type GeneratedData = typeof SidebarContainer.prototype.generated; @@ -16,7 +17,8 @@ type Props = {| ...InjectedOrGenerated, |}; type InjectedProps = {| - +isRevampLayout: boolean, + +selectedLayout: string, + +renderLayoutComponent: LayoutComponentMap => Node, |}; type AllProps = {| ...Props, ...InjectedProps |}; @@ -30,8 +32,8 @@ class SidebarContainer extends Component { const { stores } = this.generated; const { profile } = stores; - return this.props.isRevampLayout ? ( - { this.generated.actions.router.goToRoute.trigger({ route: category.route, @@ -40,16 +42,20 @@ class SidebarContainer extends Component { isActiveCategory={category => this.generated.stores.app.currentRoute.startsWith(category.route) } - categories={allCategoriesRevamp.filter(category => + categories={allCategories.filter(category => category.isVisible({ hasAnyWallets: this.generated.stores.wallets.hasAnyWallets, selected: this.generated.stores.wallets.selected, currentRoute: this.generated.stores.app.currentRoute, }) )} + onToggleSidebar={this.toggleSidebar} + isSidebarExpanded={profile.isSidebarExpanded} /> - ) : ( - { this.generated.actions.router.goToRoute.trigger({ route: category.route, @@ -58,17 +64,20 @@ class SidebarContainer extends Component { isActiveCategory={category => this.generated.stores.app.currentRoute.startsWith(category.route) } - categories={allCategories.filter(category => + categories={allCategoriesRevamp.filter(category => category.isVisible({ hasAnyWallets: this.generated.stores.wallets.hasAnyWallets, selected: this.generated.stores.wallets.selected, currentRoute: this.generated.stores.app.currentRoute, }) )} - onToggleSidebar={this.toggleSidebar} - isSidebarExpanded={profile.isSidebarExpanded} /> ); + + return this.props.renderLayoutComponent({ + CLASSIC: SidebarComponent, + REVAMP: SidebarRevampComponent, + }); } @computed get generated(): {| diff --git a/packages/yoroi-extension/app/containers/SidebarRevampContainer.js b/packages/yoroi-extension/app/containers/SidebarRevampContainer.js deleted file mode 100644 index df13a88d4b..0000000000 --- a/packages/yoroi-extension/app/containers/SidebarRevampContainer.js +++ /dev/null @@ -1,81 +0,0 @@ -// @flow -import type { Node } from 'react'; -import React, { Component } from 'react'; -import { observer } from 'mobx-react'; -import { computed } from 'mobx'; -import SidebarRevamp from '../components/topbar/SidebarRevamp'; -import type { InjectedOrGenerated } from '../types/injectedPropsType'; -import { allCategoriesRevamp } from '../stores/stateless/sidebarCategories'; -import { PublicDeriver } from '../api/ada/lib/storage/models/PublicDeriver'; - -export type GeneratedData = typeof SidebarRevampContainer.prototype.generated; - -@observer -export default class SidebarRevampContainer extends Component> { - render(): Node { - return ( - { - this.generated.actions.router.goToRoute.trigger({ - route: category.route, - }); - }} - isActiveCategory={category => - this.generated.stores.app.currentRoute.startsWith(category.route) - } - categories={allCategoriesRevamp.filter(category => - category.isVisible({ - hasAnyWallets: this.generated.stores.wallets.hasAnyWallets, - selected: this.generated.stores.wallets.selected, - currentRoute: this.generated.stores.app.currentRoute, - }) - )} - /> - ); - } - - @computed get generated(): {| - actions: {| - router: {| - goToRoute: {| - trigger: (params: {| - publicDeriver?: null | PublicDeriver<>, - params?: ?any, - route: string, - |}) => void, - |}, - |}, - |}, - stores: {| - app: {| currentRoute: string |}, - wallets: {| - hasAnyWallets: boolean, - selected: null | PublicDeriver<>, - |}, - |}, - |} { - if (this.props.generated !== undefined) { - return this.props.generated; - } - if (this.props.stores == null || this.props.actions == null) { - throw new Error(`${nameof(SidebarRevampContainer)} no way to generated props`); - } - const { stores, actions } = this.props; - return Object.freeze({ - stores: { - app: { - currentRoute: stores.app.currentRoute, - }, - wallets: { - selected: stores.wallets.selected, - hasAnyWallets: stores.wallets.hasAnyWallets, - }, - }, - actions: { - router: { - goToRoute: { trigger: actions.router.goToRoute.trigger }, - }, - }, - }); - } -} diff --git a/packages/yoroi-extension/app/themes/context/layout.js b/packages/yoroi-extension/app/themes/context/layout.js index db4269d229..8791e0b99a 100644 --- a/packages/yoroi-extension/app/themes/context/layout.js +++ b/packages/yoroi-extension/app/themes/context/layout.js @@ -3,13 +3,18 @@ import React from 'react'; import type { Node } from 'react'; import { THEMES, THEMES_REVAMP } from '..'; -type layoutState = {| - selected: string, - [key: 'CLASSIC' | 'REVAMP']: {| +type Layouts = 'CLASSIC' | 'REVAMP'; +export type LayoutComponentMap = {| + [key: Layouts]: Node, +|}; +type LayoutInitialState = {| + selected: Layouts, + [key: Layouts]: {| themes: Object, |}, |}; -const initialState: layoutState = { + +const initialState: LayoutInitialState = { selected: 'CLASSIC', CLASSIC: { themes: THEMES, @@ -40,13 +45,17 @@ const LayoutProvider = (props: Object): Node => { selectedLayout: state.selected, isRevampLayout: state.selected === 'REVAMP', changeLayout: () => dispatch({ type: 'CHANGE_LAYOUT' }), + renderLayoutComponent: (layoutMap: LayoutComponentMap = {}) => { + const selectedComponent = layoutMap[state.selected]; + return selectedComponent; + }, }} {...props} /> ); }; -function useLayout(): layoutState { +function useLayout(): LayoutInitialState { const context = React.useContext(LayoutContext); if (!context) { throw new Error('useLayout must be used within a LayoutProvider');