From 8771c68d17f423a45d02d9eb1173cfda4678bc34 Mon Sep 17 00:00:00 2001 From: Patrick Lawler Date: Wed, 15 Aug 2018 18:04:59 -0400 Subject: [PATCH 1/4] GH-339 Ghostery hub navigation stub --- _locales/en/messages.json | 3 + app/hub/{components => }/App.jsx | 6 +- app/hub/Views/HomeView/HomeView.jsx | 71 +++++++++++------- app/hub/Views/HomeView/HomeView.scss | 6 ++ .../index.js => HomeView/HomeViewActions.js} | 12 ++- .../HomeViewConstants.js} | 6 +- app/hub/Views/HomeView/HomeViewContainer.jsx | 52 +++++++++++++ app/hub/Views/HomeView/HomeViewReducer.js | 31 ++++++++ app/hub/Views/HomeView/index.js | 28 ++++++- .../Views/SetupView/SetupViewContainer.jsx | 21 +++--- .../SideNavigationView.jsx} | 28 +++++-- .../SideNavigationView.scss | 68 +++++++++++++++++ app/hub/Views/TutorialView/TutorialView.jsx | 4 +- app/hub/Views/TutorialView/TutorialView.scss | 41 +++++++++++ .../Views/TutorialView/TutorialViewActions.js | 9 ++- .../TutorialView/TutorialViewConstants.js | 3 +- .../TutorialView/TutorialViewContainer.jsx | 50 ++++++------- .../Views/TutorialView/TutorialViewReducer.js | 73 +++++++++++++++++++ app/hub/Views/TutorialView/index.js | 29 +++++++- .../TutorialAntiSuiteView.jsx | 33 +-------- .../TutorialAntiSuiteViewContainer.jsx | 54 ++++++++++++++ .../TutorialAntiSuiteView/index.js | 27 ++++++- .../TutorialBlockingView.jsx | 29 +------- .../TutorialBlockingViewContainer.jsx | 54 ++++++++++++++ .../TutorialBlockingView/index.js | 25 ++++++- .../TutorialLayoutView/TutorialLayoutView.jsx | 25 +++++++ .../TutorialLayoutViewContainer.jsx | 54 ++++++++++++++ .../TutorialViews/TutorialLayoutView/index.js | 37 ++++++++++ .../TutorialNavigationContainer.jsx | 53 +++++++++++--- .../TutorialViews/TutorialNavigation/index.js | 24 +++++- .../TutorialSimpleDetailedView.jsx | 50 ------------- .../TutorialTrackerListView.jsx | 31 +------- .../TutorialTrackerListViewContainer.jsx | 54 ++++++++++++++ .../TutorialTrackerListView/index.js | 25 ++++++- .../TutorialTrustRestrictView.jsx | 50 ------------- .../TutorialTrustView/TutorialTrustView.jsx} | 30 +++----- .../TutorialTrustViewContainer.jsx | 54 ++++++++++++++ .../TutorialViews/TutorialTrustView/index.js | 37 ++++++++++ .../TutorialVideoView/TutorialVideoView.jsx | 29 +------- .../TutorialVideoViewContainer.jsx | 54 ++++++++++++++ .../TutorialViews/TutorialVideoView/index.js | 25 ++++++- app/hub/createStore.js | 4 + app/hub/index.jsx | 2 +- app/images/hub/ghosty-dialogue.svg | 25 +++++++ app/scss/hub.scss | 22 +++++- app/scss/partials/_hub_side_navigation.scss | 24 ------ 46 files changed, 1104 insertions(+), 368 deletions(-) rename app/hub/{components => }/App.jsx (88%) create mode 100644 app/hub/Views/HomeView/HomeView.scss rename app/hub/Views/{TutorialViews/TutorialTrustRestrictView/index.js => HomeView/HomeViewActions.js} (65%) rename app/hub/Views/{TutorialViews/TutorialSimpleDetailedView/index.js => HomeView/HomeViewConstants.js} (64%) create mode 100644 app/hub/Views/HomeView/HomeViewContainer.jsx create mode 100644 app/hub/Views/HomeView/HomeViewReducer.js rename app/hub/{components/SideNavigation.jsx => Views/SideNavigationView/SideNavigationView.jsx} (72%) create mode 100644 app/hub/Views/SideNavigationView/SideNavigationView.scss create mode 100644 app/hub/Views/TutorialView/TutorialView.scss create mode 100644 app/hub/Views/TutorialView/TutorialViewReducer.js create mode 100644 app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialLayoutView/index.js delete mode 100644 app/hub/Views/TutorialViews/TutorialSimpleDetailedView/TutorialSimpleDetailedView.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx delete mode 100644 app/hub/Views/TutorialViews/TutorialTrustRestrictView/TutorialTrustRestrictView.jsx rename app/{scss/partials/_hub_other_partials.scss => hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx} (51%) create mode 100644 app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx create mode 100644 app/hub/Views/TutorialViews/TutorialTrustView/index.js create mode 100644 app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx create mode 100644 app/images/hub/ghosty-dialogue.svg delete mode 100644 app/scss/partials/_hub_side_navigation.scss diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 05d4804bc..9f4b5584d 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1593,6 +1593,9 @@ "setup_upgrade_button_go": { "message": "Set Me Up" }, + "hub_home_page_title": { + "message": "Ghostery Hub - Home" + }, "hub_setup_page_title": { "message": "Ghostery Hub - Setup" }, diff --git a/app/hub/components/App.jsx b/app/hub/App.jsx similarity index 88% rename from app/hub/components/App.jsx rename to app/hub/App.jsx index 1dd755e9a..060d8c0a3 100644 --- a/app/hub/components/App.jsx +++ b/app/hub/App.jsx @@ -14,7 +14,7 @@ */ import React, { Component } from 'react'; -import SideNavigation from './SideNavigation'; +import SideNavigation from './Views/SideNavigationView/SideNavigationView'; /** * @class Implements the container App for the Ghostery Hub @@ -33,10 +33,10 @@ class App extends Component { location: 'list', type: 'link', href: '/', icon: 'home', text: 'Home' }, { - location: 'list', type: 'link', href: '/setup/1', icon: 'home', text: 'Customize Setup' + location: 'list', type: 'link', href: '/setup', icon: 'home', text: 'Customize Setup' }, { - location: 'list', type: 'link', href: '/tutorial/1', icon: 'home', text: 'Visit Tutorial' + location: 'list', type: 'link', href: '/tutorial', icon: 'home', text: 'Visit Tutorial' }, { location: 'list', type: 'link', href: '/supporter', icon: 'home', text: 'Become a Ghostery Supporter' diff --git a/app/hub/Views/HomeView/HomeView.jsx b/app/hub/Views/HomeView/HomeView.jsx index 1dc179ba9..41bae253a 100644 --- a/app/hub/Views/HomeView/HomeView.jsx +++ b/app/hub/Views/HomeView/HomeView.jsx @@ -13,38 +13,55 @@ * ToDo: Update this file. */ -import React, { Component } from 'react'; +import React from 'react'; /** * @class Implement the Home View for the Ghostery Hub - * @extends Component * @memberof HubComponents */ -class HomeView extends Component { - constructor(props) { - super(props); +const HomeView = () => ( +
+
+
+
+
+
+

Ghostery is Ready!

+

you are now protected with the Ghostery recommended default settings.

+ Start browsing! + +
+
+
+
+ Optimze your ghostery experience +
+
+ Create Account +
+
+
+
+ tutorial +
+
+ customize setup +
+
+
+
+ become a ghostery support text +
+
+ support button +
+
+
+); - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Home View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} export default HomeView; diff --git a/app/hub/Views/HomeView/HomeView.scss b/app/hub/Views/HomeView/HomeView.scss new file mode 100644 index 000000000..1e7f4a008 --- /dev/null +++ b/app/hub/Views/HomeView/HomeView.scss @@ -0,0 +1,6 @@ +.ghosty-dialogue { + height: 156px; + background-image: url('../images/hub/ghosty-dialogue.svg'); + background-repeat: no-repeat; + background-size: contain; +} diff --git a/app/hub/Views/TutorialViews/TutorialTrustRestrictView/index.js b/app/hub/Views/HomeView/HomeViewActions.js similarity index 65% rename from app/hub/Views/TutorialViews/TutorialTrustRestrictView/index.js rename to app/hub/Views/HomeView/HomeViewActions.js index d3cd1f6c2..3cb00b75f 100644 --- a/app/hub/Views/TutorialViews/TutorialTrustRestrictView/index.js +++ b/app/hub/Views/HomeView/HomeViewActions.js @@ -1,5 +1,5 @@ /** - * Point of entry index.js file for Tutorial Trust/Restrict View + * Home View Action creators * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -10,7 +10,11 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { TOGGLE_ANALYTICS } from './HomeViewConstants'; -import TutorialTrustRestrictView from './TutorialTrustRestrictView'; - -export default TutorialTrustRestrictView; +export function toggleAnalytics(data) { + return { + type: TOGGLE_ANALYTICS, + data, + }; +} diff --git a/app/hub/Views/TutorialViews/TutorialSimpleDetailedView/index.js b/app/hub/Views/HomeView/HomeViewConstants.js similarity index 64% rename from app/hub/Views/TutorialViews/TutorialSimpleDetailedView/index.js rename to app/hub/Views/HomeView/HomeViewConstants.js index 41d76d8af..a5e278371 100644 --- a/app/hub/Views/TutorialViews/TutorialSimpleDetailedView/index.js +++ b/app/hub/Views/HomeView/HomeViewConstants.js @@ -1,5 +1,5 @@ /** - * Point of entry index.js file for Tutorial Simple or Detailed View + * Custom Home Constants * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -11,6 +11,4 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import TutorialSimpleDetailedView from './TutorialSimpleDetailedView'; - -export default TutorialSimpleDetailedView; +export const TOGGLE_ANALYTICS = 'TOGGLE_ANALYTICS'; diff --git a/app/hub/Views/HomeView/HomeViewContainer.jsx b/app/hub/Views/HomeView/HomeViewContainer.jsx new file mode 100644 index 000000000..e8984aa39 --- /dev/null +++ b/app/hub/Views/HomeView/HomeViewContainer.jsx @@ -0,0 +1,52 @@ +/** + * Tutorial View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React from 'react'; +import PropTypes from 'prop-types'; + +import HomeView from './HomeView'; + +/** + * @class Implement the Tutorial View Container for the Ghostery Hub + * @extends Component + * @memberof HubContainers + */ +class HomeViewContainer extends React.Component { + constructor(props) { + super(props); + const title = t('hub_home_page_title'); + window.document.title = title; + } + + /** + * React's required render function. Returns JSX + * @return {JSX} JSX for rendering the Tutorial View of the Hub app + */ + render() { + return ; + } +} + +HomeViewContainer.propTypes = { + home: PropTypes.shape({ + enable_human_web: PropTypes.bool, + }), +}; + +HomeViewContainer.defaultProps = { + home: { + enable_human_web: false, + }, +}; + +export default HomeViewContainer; diff --git a/app/hub/Views/HomeView/HomeViewReducer.js b/app/hub/Views/HomeView/HomeViewReducer.js new file mode 100644 index 000000000..802425b52 --- /dev/null +++ b/app/hub/Views/HomeView/HomeViewReducer.js @@ -0,0 +1,31 @@ +/** + * Reducer used in the Home View + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ +import { TOGGLE_ANALYTICS } from './HomeViewConstants'; + +const initialState = {}; + +function HomeViewReducer(state = initialState, action) { + switch (action.type) { + case TOGGLE_ANALYTICS: { + return Object.assign({}, state, { + home: { + enable_human_web: action.data.enable_human_web + }, + }); + } + + default: return state; + } +} + +export default HomeViewReducer; diff --git a/app/hub/Views/HomeView/index.js b/app/hub/Views/HomeView/index.js index 57c9415fc..b8a2de841 100644 --- a/app/hub/Views/HomeView/index.js +++ b/app/hub/Views/HomeView/index.js @@ -10,7 +10,31 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import HomeView from './HomeView'; +import * as actions from './HomeViewActions'; +import HomeViewReducer from './HomeViewReducer'; +import HomeViewContainer from './HomeViewContainer'; -export default HomeView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.home); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign(actions), dispatch), +}); + +export const reducer = HomeViewReducer; + +export default connect(mapStateToProps, mapDispatchToProps)(HomeViewContainer); diff --git a/app/hub/Views/SetupView/SetupViewContainer.jsx b/app/hub/Views/SetupView/SetupViewContainer.jsx index e4b3bf955..8d2a1cabc 100644 --- a/app/hub/Views/SetupView/SetupViewContainer.jsx +++ b/app/hub/Views/SetupView/SetupViewContainer.jsx @@ -12,7 +12,7 @@ */ import React from 'react'; -import { NavLink } from 'react-router-dom'; +import { NavLink, withRouter } from 'react-router-dom'; import QueryString from 'query-string'; import PropTypes from 'prop-types'; import SetupView from './SetupView'; @@ -33,16 +33,6 @@ import SetupDoneView from '../SetupViews/SetupDoneView'; class SetupViewContainer extends React.Component { constructor(props) { super(props); - this.state = { - sendMountActions: false, - showModal: false, - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { const title = t('hub_setup_page_title'); window.document.title = title; @@ -60,6 +50,13 @@ class SetupViewContainer extends React.Component { this._setDefaultSettings(); } }); + + this.state = { + sendMountActions: false, + showModal: false, + }; + + this.props.history.push('/setup/1'); } /** @@ -267,4 +264,4 @@ SetupViewContainer.defaultProps = { }, }; -export default SetupViewContainer; +export default withRouter(SetupViewContainer); diff --git a/app/hub/components/SideNavigation.jsx b/app/hub/Views/SideNavigationView/SideNavigationView.jsx similarity index 72% rename from app/hub/components/SideNavigation.jsx rename to app/hub/Views/SideNavigationView/SideNavigationView.jsx index 22e170529..d3eacb0b6 100644 --- a/app/hub/components/SideNavigation.jsx +++ b/app/hub/Views/SideNavigationView/SideNavigationView.jsx @@ -21,7 +21,7 @@ import { NavLink } from 'react-router-dom'; * @extends Component * @memberof HubComponents */ -class SideNavigation extends Component { +class SideNavigationView extends Component { constructor(props) { super(props); @@ -54,14 +54,24 @@ class SideNavigation extends Component { * A helper function for rendering a Side Navigation List Item * @return {JSX} JSX for the Navigation Item */ + + hasNestedRoutes(route) { + const parentRoutes = ['setup', 'tutorial']; + return parentRoutes.some(parentRoute => route.href.includes(parentRoute)); + } + _renderItem(item = {}, index) { switch (item.type) { case 'separator': return
; case 'link': return ( - -
{item.text}
+ +
{item.text}
+
+
+
+
); default: @@ -77,12 +87,18 @@ class SideNavigation extends Component { const { topItems, listItems, bottomItems } = this.state; return ( -
+
{topItems.map((item, i) => this._renderItem(item, i))}
- {listItems.map((item, i) => this._renderItem(item, i))} +
    + {listItems.map((item, i) => ( +
  • + {this._renderItem(item, i)} +
  • + ))} +
{bottomItems.map((item, i) => this._renderItem(item, i))} @@ -92,4 +108,4 @@ class SideNavigation extends Component { } } -export default SideNavigation; +export default SideNavigationView; diff --git a/app/hub/Views/SideNavigationView/SideNavigationView.scss b/app/hub/Views/SideNavigationView/SideNavigationView.scss new file mode 100644 index 000000000..18a7de0c7 --- /dev/null +++ b/app/hub/Views/SideNavigationView/SideNavigationView.scss @@ -0,0 +1,68 @@ +/** + * Ghostery Hub - Side Navigation Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +.App__leftNavigation { + background-color: $hoki; + height: 100%; + min-width: 200px; + max-width: 200px; + color: $white; + ul { + list-style: none; + margin-left: 20px; + li { + height: 80px; + } + } + a { + height: 80px; + .flex-child-auto { + max-width: 160px; + } + color: $white; + &.active { + text-decoration: underline; + } + } +} +// Side Navigation +.SideNavigation__container { + background-color: $hoki; + .SideNavigation__top { + min-height: 80px; + background-color: $mystic; + } + .SideNavigation__bottom { + margin: 0px 0px 20px 20px; + } + .active .arrow-left { + position: relative; + height: 80px; + width: 20px; + background-color: transparent; + .arrow-left-bottom { + width: 0; + height: 0; + border-style: solid; + border-width: 0 20px 40px 0; + border-color: transparent $white transparent transparent; + } + .arrow-left-top { + width: 0; + height: 0; + border-style: solid; + border-width: 0 0 40px 20px; + border-color: transparent transparent $white transparent; + } + } +} diff --git a/app/hub/Views/TutorialView/TutorialView.jsx b/app/hub/Views/TutorialView/TutorialView.jsx index f322f247a..f60a85a12 100644 --- a/app/hub/Views/TutorialView/TutorialView.jsx +++ b/app/hub/Views/TutorialView/TutorialView.jsx @@ -32,14 +32,14 @@ const TutorialView = props => ( path={step.path} render={() => (
- +
)} /> ))}
- +
); diff --git a/app/hub/Views/TutorialView/TutorialView.scss b/app/hub/Views/TutorialView/TutorialView.scss new file mode 100644 index 000000000..0011ae2c8 --- /dev/null +++ b/app/hub/Views/TutorialView/TutorialView.scss @@ -0,0 +1,41 @@ +/** + * Tutorial View Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +// purple rectangle outline +.rectangle-1 { + width: 120px; + height: 43px; + border-radius: 7.2px; + box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.5); + border: solid 2.7px #930194; + transform: scale(0); + -webkit-animation: zoom .5s; + animation: zoom .5s; + -webkit-animation-fill-mode: forwards; + animation-fill-mode: forwards; + -webkit-animation-delay: 1s; + animation-delay: 1s; +} + + +@-webkit-keyframes zoom { + 100% { + -webkit-transform: scale(1,1); + } +} + +@keyframes zoom { + 100% { + transform: scale(1,1); + } +} diff --git a/app/hub/Views/TutorialView/TutorialViewActions.js b/app/hub/Views/TutorialView/TutorialViewActions.js index 5e16af138..3cd06cde5 100644 --- a/app/hub/Views/TutorialView/TutorialViewActions.js +++ b/app/hub/Views/TutorialView/TutorialViewActions.js @@ -11,7 +11,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import { INIT_TUTORIAL_PROPS } from './TutorialViewConstants'; +import { INIT_TUTORIAL_PROPS, SET_TUTORIAL_NAVIGATION } from './TutorialViewConstants'; export function initTutorialProps(data) { return { @@ -19,3 +19,10 @@ export function initTutorialProps(data) { data, }; } + +export function setTutorialNavigation(data) { + return { + type: SET_TUTORIAL_NAVIGATION, + data, + }; +} diff --git a/app/hub/Views/TutorialView/TutorialViewConstants.js b/app/hub/Views/TutorialView/TutorialViewConstants.js index 21aac1be4..47adcc798 100644 --- a/app/hub/Views/TutorialView/TutorialViewConstants.js +++ b/app/hub/Views/TutorialView/TutorialViewConstants.js @@ -11,5 +11,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -// Tutorial View export const INIT_TUTORIAL_PROPS = 'INIT_TUTORIAL_PROPS'; + +export const SET_TUTORIAL_NAVIGATION = 'SET_TUTORIAL_NAVIGATION'; diff --git a/app/hub/Views/TutorialView/TutorialViewContainer.jsx b/app/hub/Views/TutorialView/TutorialViewContainer.jsx index 2b0c2543c..b8d5668c9 100644 --- a/app/hub/Views/TutorialView/TutorialViewContainer.jsx +++ b/app/hub/Views/TutorialView/TutorialViewContainer.jsx @@ -12,18 +12,16 @@ */ import React from 'react'; -import { connect } from 'react-redux'; -import { bindActionCreators } from 'redux'; +import { withRouter } from 'react-router-dom'; import TutorialView from './TutorialView'; -import * as actions from './TutorialViewActions'; // Component Views import TutorialVideoView from '../TutorialViews/TutorialVideoView'; import TutorialTrackerListView from '../TutorialViews/TutorialTrackerListView'; -import TutorialSimpleDetailedView from '../TutorialViews/TutorialSimpleDetailedView'; +import TutorialLayoutView from '../TutorialViews/TutorialLayoutView'; import TutorialBlockingView from '../TutorialViews/TutorialBlockingView'; -import TutorialTrustRestrictView from '../TutorialViews/TutorialTrustRestrictView'; +import TutorialTrustView from '../TutorialViews/TutorialTrustView'; import TutorialAntiSuiteView from '../TutorialViews/TutorialAntiSuiteView'; /** @@ -35,9 +33,12 @@ class TutorialViewContainer extends React.Component { /** * Lifecycle Event */ - componentWillMount() { + constructor(props) { + super(props); const title = ''; window.document.title = title; + this.props.actions.initTutorialProps(this.props.tutorial); + this.props.history.push('/tutorial/1'); } /** @@ -60,7 +61,7 @@ class TutorialViewContainer extends React.Component { { index: 3, path: '/tutorial/3', - bodyComponent: TutorialSimpleDetailedView, + bodyComponent: TutorialLayoutView, }, { index: 4, @@ -70,7 +71,7 @@ class TutorialViewContainer extends React.Component { { index: 5, path: '/tutorial/5', - bodyComponent: TutorialTrustRestrictView, + bodyComponent: TutorialTrustView, }, { index: 6, @@ -84,24 +85,19 @@ class TutorialViewContainer extends React.Component { } // Default props used throughout the Tutorial flow -TutorialViewContainer.defaultProps = {}; +TutorialViewContainer.defaultProps = { + tutorial: { + navigation: { + activeIndex: 0, + hrefPrev: false, + hrefNext: false, + hrefDone: false, + textPrev: false, + textNext: false, + textDone: false, + }, + }, +}; -/** - * Map redux store state properties to the component's own properties. - * @param {Object} state entire Redux store's state - * @return {function} this function returns a plain object, which will be merged into the component's props - * @memberof HubContainers - */ -const mapStateToProps = () => Object.assign({}); - -/** - * Bind the component's action creators using Redux's bindActionCreators. - * @param {function} dispatch redux store method which dispatches actions - * @return {function} to be used as an argument in redux connect call - * @memberof SetupContainers - */ -const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(Object.assign(actions), dispatch), -}); -export default connect(mapStateToProps, mapDispatchToProps)(TutorialViewContainer); +export default withRouter(TutorialViewContainer); diff --git a/app/hub/Views/TutorialView/TutorialViewReducer.js b/app/hub/Views/TutorialView/TutorialViewReducer.js new file mode 100644 index 000000000..6e8fb4d97 --- /dev/null +++ b/app/hub/Views/TutorialView/TutorialViewReducer.js @@ -0,0 +1,73 @@ +/** + * Reducer used throughout the Tutorial View's flow + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ +import { INIT_TUTORIAL_PROPS, SET_TUTORIAL_NAVIGATION } from './TutorialViewConstants'; + +const initialState = {}; + +function TutorialViewReducer(state = initialState, action) { + switch (action.type) { + // Tutorial View + case INIT_TUTORIAL_PROPS: { + const { + activeIndex, + hrefPrev, + hrefNext, + hrefDone, + textPrev, + textNext, + textDone, + } = action.data.navigation; + return Object.assign({}, state, { + tutorial: { + navigation: { + activeIndex, + hrefPrev, + hrefNext, + hrefDone, + textPrev, + textNext, + textDone, + } + }, + }); + } + case SET_TUTORIAL_NAVIGATION: { + const { + activeIndex, + hrefPrev, + hrefNext, + hrefDone, + textPrev, + textNext, + textDone, + } = action.data; + return Object.assign({}, state, { + tutorial: Object.assign({}, state.tutorial, { + navigation: { + activeIndex, + hrefPrev, + hrefNext, + hrefDone, + textPrev, + textNext, + textDone, + }, + }), + }); + } + + default: return state; + } +} + +export default TutorialViewReducer; diff --git a/app/hub/Views/TutorialView/index.js b/app/hub/Views/TutorialView/index.js index 9ac71d2ac..f4ddb0dbb 100644 --- a/app/hub/Views/TutorialView/index.js +++ b/app/hub/Views/TutorialView/index.js @@ -10,7 +10,34 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +// import { connect } from 'react-redux'; +// import { bindActionCreators } from 'redux'; +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import * as actions from './TutorialViewActions'; import TutorialViewContainer from './TutorialViewContainer'; +import TutorialViewReducer from './TutorialViewReducer'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign(actions), dispatch), +}); + +export const reducer = TutorialViewReducer; -export default TutorialViewContainer; +export default connect(mapStateToProps, mapDispatchToProps)(TutorialViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx index af62aae7d..55533308f 100644 --- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteView.jsx @@ -1,5 +1,5 @@ /** - * Tutorial Anti-Suite View Component + * Tutorial Anti Suite View Component * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -13,38 +13,13 @@ * ToDo: Update this file. */ -import React, { Component } from 'react'; +import React from 'react'; /** - * @class Implement the Tutorial Anti-Suite View for the Ghostery Hub + * @class Implement the Tutorial Anti Suite View for the Ghostery Hub * @extends Component * @memberof HubComponents */ -class TutorialAntiSuiteView extends Component { - constructor(props) { - super(props); - - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Anti-Suite View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} +const TutorialAntiSuiteView = () =>
Ghostery Hub - Tutorial Anti Suite View
; export default TutorialAntiSuiteView; diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx new file mode 100644 index 000000000..3f6ea2155 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Anti Suite View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialAntiSuiteView from './TutorialAntiSuiteView'; + +/** + * @class Implement the Tutorial Anti Suite View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialAntiSuiteViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: `/tutorial/${index - 1}`, + hrefNext: '/', + hrefDone: '/', + textPrev: t('hub_setup_nav_previous'), + textNext: t('hub_setup_nav_done'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialAntiSuiteViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialAntiSuiteViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js index 4b7ea65d6..fe2e0d114 100644 --- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js @@ -1,5 +1,5 @@ /** - * Point of entry index.js file for Tutorial Anti-Suite View + * Point of entry index.js file for Tutorial Anti Suite View * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -10,7 +10,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import TutorialAntiSuiteView from './TutorialAntiSuiteView'; +import TutorialAntiSuiteViewContainer from './TutorialAntiSuiteViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; -export default TutorialAntiSuiteView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialAntiSuiteViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx index e6c623c3e..11e5c57f7 100644 --- a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx +++ b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingView.jsx @@ -13,38 +13,13 @@ * ToDo: Update this file. */ -import React, { Component } from 'react'; +import React from 'react'; /** * @class Implement the Tutorial Blocking View for the Ghostery Hub * @extends Component * @memberof HubComponents */ -class TutorialBlockingView extends Component { - constructor(props) { - super(props); - - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Blocking View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} +const TutorialBlockingView = () =>
Ghostery Hub - Tutorial Blocking View
; export default TutorialBlockingView; diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx new file mode 100644 index 000000000..d05ae1fcf --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialBlockingView/TutorialBlockingViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Blocking View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialBlockingView from './TutorialBlockingView'; + +/** + * @class Implement the Tutorial Blocking View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialBlockingViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: `/tutorial/${index - 1}`, + hrefNext: `/tutorial/${index + 1}`, + hrefDone: '/', + textPrev: t('hub_setup_nav_previous'), + textNext: t('hub_setup_nav_next'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialBlockingViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialBlockingViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/index.js b/app/hub/Views/TutorialViews/TutorialBlockingView/index.js index 22d97f1e0..2910d3795 100644 --- a/app/hub/Views/TutorialViews/TutorialBlockingView/index.js +++ b/app/hub/Views/TutorialViews/TutorialBlockingView/index.js @@ -10,7 +10,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import TutorialBlockingView from './TutorialBlockingView'; +import TutorialBlockingViewContainer from './TutorialBlockingViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; -export default TutorialBlockingView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialBlockingViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx new file mode 100644 index 000000000..a34ddfb50 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutView.jsx @@ -0,0 +1,25 @@ +/** + * Tutorial Layout View Component + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + * + * ToDo: Update this file. + */ + +import React from 'react'; + +/** + * @class Implement the Tutorial Layout View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +const TutorialLayoutView = () =>
Ghostery Hub - Tutorial Simple / Detailed Layout View
; + +export default TutorialLayoutView; diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx new file mode 100644 index 000000000..3cdb56fba --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialLayoutView/TutorialLayoutViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Layout View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialLayoutView from './TutorialLayoutView'; + +/** + * @class Implement the Tutorial Layout View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialLayoutViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: `/tutorial/${index - 1}`, + hrefNext: `/tutorial/${index + 1}`, + hrefDone: '/', + textPrev: t('hub_setup_nav_previous'), + textNext: t('hub_setup_nav_next'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialLayoutViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialLayoutViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/index.js b/app/hub/Views/TutorialViews/TutorialLayoutView/index.js new file mode 100644 index 000000000..0c3e0f4c0 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialLayoutView/index.js @@ -0,0 +1,37 @@ +/** + * Point of entry index.js file for Tutorial Layout View + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import TutorialLayoutViewContainer from './TutorialLayoutViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialLayoutViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialNavigation/TutorialNavigationContainer.jsx b/app/hub/Views/TutorialViews/TutorialNavigation/TutorialNavigationContainer.jsx index 7daf171a6..5c18084de 100644 --- a/app/hub/Views/TutorialViews/TutorialNavigation/TutorialNavigationContainer.jsx +++ b/app/hub/Views/TutorialViews/TutorialNavigation/TutorialNavigationContainer.jsx @@ -12,6 +12,7 @@ */ import React from 'react'; +import PropTypes from 'prop-types'; import { SteppedNavigation } from '../../../../shared-components'; /** @@ -19,19 +20,49 @@ import { SteppedNavigation } from '../../../../shared-components'; * @extends Component * @memberof HubComponents */ -const TutorialNavigationContainer = () => { - const childProps = { - totalSteps: 6, - activeIndex: 1, - hrefPrev: false, - hrefNext: '/tutorial/2', - hrefDone: '/', - textPrev: false, - textNext: '', - textDone: '', + +const TutorialNavigationContainer = (props) => { + const { totalSteps, tutorial } = props; + const { navigation } = tutorial; + const navigationProps = { + totalSteps, + ...navigation, }; + return ; +}; - return ; +// PropTypes ensure we pass required props of the correct type +TutorialNavigationContainer.propTypes = { + totalSteps: PropTypes.number.isRequired, + tutorial: PropTypes.shape({ + navigation: PropTypes.shape({ + activeIndex: PropTypes.number.isRequired, + hrefPrev: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + hrefNext: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + hrefDone: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + textPrev: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + textNext: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + textDone: PropTypes.oneOfType([ + PropTypes.bool, + PropTypes.string, + ]).isRequired, + }).isRequired, + }).isRequired }; export default TutorialNavigationContainer; diff --git a/app/hub/Views/TutorialViews/TutorialNavigation/index.js b/app/hub/Views/TutorialViews/TutorialNavigation/index.js index 00610531a..71760758a 100644 --- a/app/hub/Views/TutorialViews/TutorialNavigation/index.js +++ b/app/hub/Views/TutorialViews/TutorialNavigation/index.js @@ -11,6 +11,28 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + import TutorialNavigationContainer from './TutorialNavigationContainer'; -export default TutorialNavigationContainer; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof SetupContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { + }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialNavigationContainer); diff --git a/app/hub/Views/TutorialViews/TutorialSimpleDetailedView/TutorialSimpleDetailedView.jsx b/app/hub/Views/TutorialViews/TutorialSimpleDetailedView/TutorialSimpleDetailedView.jsx deleted file mode 100644 index a5f530f15..000000000 --- a/app/hub/Views/TutorialViews/TutorialSimpleDetailedView/TutorialSimpleDetailedView.jsx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Tutorial Simple and Detailed View Component - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2018 Ghostery, Inc. All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0 - * - * ToDo: Update this file. - */ - -import React, { Component } from 'react'; - -/** - * @class Implement the Tutorial Simple and Detailed View for the Ghostery Hub - * @extends Component - * @memberof HubComponents - */ -class TutorailSimpleDetailedView extends Component { - constructor(props) { - super(props); - - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Simple and Detailed View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} - -export default TutorailSimpleDetailedView; diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListView.jsx b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListView.jsx index d9eb392b6..95eb3fa89 100644 --- a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListView.jsx +++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListView.jsx @@ -13,38 +13,13 @@ * ToDo: Update this file. */ -import React, { Component } from 'react'; +import React from 'react'; /** * @class Implement the Tutorial Tracker List View for the Ghostery Hub * @extends Component * @memberof HubComponents */ -class TutorailTrackerListView extends Component { - constructor(props) { - super(props); +const TutorialTrackerListView = () =>
Ghostery Hub - Tutorial Tracker List View
; - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Tracker List View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} - -export default TutorailTrackerListView; +export default TutorialTrackerListView; diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx new file mode 100644 index 000000000..ee3aba16b --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/TutorialTrackerListViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Tracker List View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialTrackerListView from './TutorialTrackerListView'; + +/** + * @class Implement the Tutorial Tracker List View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialTrackerListViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: `/tutorial/${index - 1}`, + hrefNext: `/tutorial/${index + 1}`, + hrefDone: '/', + textPrev: t('hub_setup_nav_previous'), + textNext: t('hub_setup_nav_next'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialTrackerListViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialTrackerListViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js b/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js index b1e418c3e..ca422d9ee 100644 --- a/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js +++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js @@ -10,7 +10,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import TutorialTrackerListView from './TutorialTrackerListView'; +import TutorialTrackerListViewContainer from './TutorialTrackerListViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; -export default TutorialTrackerListView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialTrackerListViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialTrustRestrictView/TutorialTrustRestrictView.jsx b/app/hub/Views/TutorialViews/TutorialTrustRestrictView/TutorialTrustRestrictView.jsx deleted file mode 100644 index ae3127a9f..000000000 --- a/app/hub/Views/TutorialViews/TutorialTrustRestrictView/TutorialTrustRestrictView.jsx +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Tutorial Trust and Restrict View Component - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2018 Ghostery, Inc. All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0 - * - * ToDo: Update this file. - */ - -import React, { Component } from 'react'; - -/** - * @class Implement the Tutorial Trust and Restrict View for the Ghostery Hub - * @extends Component - * @memberof HubComponents - */ -class TutorailTrustRestrictView extends Component { - constructor(props) { - super(props); - - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Trust and Restrict View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} - -export default TutorailTrustRestrictView; diff --git a/app/scss/partials/_hub_other_partials.scss b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx similarity index 51% rename from app/scss/partials/_hub_other_partials.scss rename to app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx index f89e813d7..d1f20107c 100644 --- a/app/scss/partials/_hub_other_partials.scss +++ b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustView.jsx @@ -1,5 +1,5 @@ /** - * Ghostery Hub - Other Sass + * Tutorial Trust View Component * * Ghostery Browser Extension * https://www.ghostery.com/ @@ -10,22 +10,16 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 * - * ToDo: Remove this file. + * ToDo: Update this file. */ -// App Scss -.App { - height: 100%; - width: 100%; - display: flex; -} -.App__leftNavigation { - height: 100%; - background-color: pink; - min-width: 200px; - max-width: 200px; -} -.App__mainContent { - height: 100%; - flex-grow: 1; -} +import React from 'react'; + +/** + * @class Implement the Tutorial Trust View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +const TutorialTrustView = () =>
Ghostery Hub - Tutorial Trust
; + +export default TutorialTrustView; diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx new file mode 100644 index 000000000..f8911318c --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialTrustView/TutorialTrustViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Trust View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialTrustView from './TutorialTrustView'; + +/** + * @class Implement the Tutorial Trust View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialTrustViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: `/tutorial/${index - 1}`, + hrefNext: `/tutorial/${index + 1}`, + hrefDone: '/', + textPrev: t('hub_setup_nav_previous'), + textNext: t('hub_setup_nav_next'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialTrustViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialTrustViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/index.js b/app/hub/Views/TutorialViews/TutorialTrustView/index.js new file mode 100644 index 000000000..7be6989b0 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialTrustView/index.js @@ -0,0 +1,37 @@ +/** + * Point of entry index.js file for Tutorial Trust View + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; + +import TutorialTrustViewContainer from './TutorialTrustViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; + +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialTrustViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoView.jsx b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoView.jsx index 9f929cba6..416c861f7 100644 --- a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoView.jsx +++ b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoView.jsx @@ -13,38 +13,13 @@ * ToDo: Update this file. */ -import React, { Component } from 'react'; +import React from 'react'; /** * @class Implement the Tutorial Video View for the Ghostery Hub * @extends Component * @memberof HubComponents */ -class TutorialVideoView extends Component { - constructor(props) { - super(props); - - this.state = { - title: '' - }; - } - - /** - * Lifecycle Event - */ - componentWillMount() { - const { title } = this.state; - window.document.title = title; - } - - /** - * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial Video View of the Hub app - */ - render() { - const { title } = this.state; - return
{title}
; - } -} +const TutorialVideoView = () =>
Ghostery Hub - Tutorial Video View
; export default TutorialVideoView; diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx new file mode 100644 index 000000000..756e654a0 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialVideoView/TutorialVideoViewContainer.jsx @@ -0,0 +1,54 @@ +/** + * Tutorial Video View Container + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import TutorialVideoView from './TutorialVideoView'; + +/** + * @class Implement the Tutorial Video View for the Ghostery Hub + * @extends Component + * @memberof HubComponents + */ +class TutorialVideoViewContainer extends Component { + constructor(props) { + super(props); + + // TODO call setTutorialNavigation action + const { index } = this.props; + this.props.actions.setTutorialNavigation({ + activeIndex: index, + hrefPrev: false, + hrefNext: `/tutorial/${index + 1}`, + hrefDone: '/', + textPrev: false, + textNext: t('hub_setup_nav_next'), + textDone: t('hub_setup_exit_flow'), + }); + } + + render() { + return ; + } +} + +// PropTypes ensure we pass required props of the correct type +TutorialVideoViewContainer.propTypes = { + index: PropTypes.number.isRequired, + actions: PropTypes.shape({ + setTutorialNavigation: PropTypes.func.isRequired, + }).isRequired, +}; + +export default TutorialVideoViewContainer; diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/index.js b/app/hub/Views/TutorialViews/TutorialVideoView/index.js index a0a33e016..f2dc50180 100644 --- a/app/hub/Views/TutorialViews/TutorialVideoView/index.js +++ b/app/hub/Views/TutorialViews/TutorialVideoView/index.js @@ -10,7 +10,28 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +import { connect } from 'react-redux'; +import { bindActionCreators } from 'redux'; -import TutorialVideoView from './TutorialVideoView'; +import TutorialVideoViewContainer from './TutorialVideoViewContainer'; +import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; -export default TutorialVideoView; +/** + * Map redux store state properties to the component's own properties. + * @param {Object} state entire Redux store's state + * @return {function} this function returns a plain object, which will be merged into the component's props + * @memberof HubContainers + */ +const mapStateToProps = state => Object.assign({}, state.tutorial); + +/** + * Bind the component's action creators using Redux's bindActionCreators. + * @param {function} dispatch redux store method which dispatches actions + * @return {function} to be used as an argument in redux connect call + * @memberof TutorialContainers + */ +const mapDispatchToProps = dispatch => ({ + actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(TutorialVideoViewContainer); diff --git a/app/hub/createStore.js b/app/hub/createStore.js index 1bf66a39f..b6e56a1a2 100644 --- a/app/hub/createStore.js +++ b/app/hub/createStore.js @@ -21,10 +21,14 @@ import { } from 'redux'; import thunk from 'redux-thunk'; +import { reducer as home } from './Views/HomeView'; import { reducer as setup } from './Views/SetupView'; +import { reducer as tutorial } from './Views/TutorialView'; const reducer = combineReducers({ setup, + tutorial, + home, }); /** diff --git a/app/hub/index.jsx b/app/hub/index.jsx index fb2a94fac..1f22f5a86 100644 --- a/app/hub/index.jsx +++ b/app/hub/index.jsx @@ -20,7 +20,7 @@ import { Provider } from 'react-redux'; import createStore from './createStore'; // Components -import App from './components/App'; +import App from './App'; // Containers import HomeView from './Views/HomeView'; diff --git a/app/images/hub/ghosty-dialogue.svg b/app/images/hub/ghosty-dialogue.svg new file mode 100644 index 000000000..6d3709603 --- /dev/null +++ b/app/images/hub/ghosty-dialogue.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/scss/hub.scss b/app/scss/hub.scss index cf556e7e2..f9e52af4a 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -18,9 +18,22 @@ html, body, #root { margin: 0; } +<<<<<<< HEAD // Foundation Overrides h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { font-family: Roboto, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; +======= +.App { + height: 100%; + width: 100%; + display: flex; + overflow-y: scroll; +} + +.App__mainContent { + height: 100%; + flex-grow: 1; +>>>>>>> sidebar height - remove tmp scss } // Helper Classes @@ -29,12 +42,13 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { .full-width { width: 100%; } .display-inline { display: inline-block; } +@import 'settings_hub'; @import './partials/_hub_mixins'; @import './partials/_hub_svgs'; -@import './partials/_hub_side_navigation'; -@import './partials/_hub_other_partials'; // ToDo: Remove this file -// Imports from ../hub directory for the Custom Setup Workflow + +@import '../hub/Views/HomeView/HomeView.scss'; +@import '../hub/Views/SideNavigationView/SideNavigationView.scss'; @import '../hub/Views/SetupView/SetupView.scss'; @import '../hub/Views/SetupViews/SetupHeader/SetupHeader.scss'; @import '../hub/Views/SetupViews/SetupBlockingView/SetupBlockingView.scss'; @@ -42,6 +56,8 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { @import '../hub/Views/SetupViews/SetupHumanWebView/SetupHumanWebView.scss'; @import '../hub/Views/SetupViews/SetupDoneView/SetupDoneView.scss'; +@import '../hub/Views/TutorialView/TutorialView.scss'; + // Imports from ../shared-components directory @import '../shared-components/Modal/Modal.scss'; @import '../shared-components/SteppedNavigation/SteppedNavigation.scss'; diff --git a/app/scss/partials/_hub_side_navigation.scss b/app/scss/partials/_hub_side_navigation.scss deleted file mode 100644 index 456496014..000000000 --- a/app/scss/partials/_hub_side_navigation.scss +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Ghostery Hub - Side Navigation Sass - * - * Ghostery Browser Extension - * https://www.ghostery.com/ - * - * Copyright 2018 Ghostery, Inc. All rights reserved. - * - * This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0 - */ - - // Side Navigation - .SideNavigation__top { - min-height: 100px; - margin: 16px; - } - .SideNavigation__list { - margin: 16px; - } - .SideNavigation__bottom { - margin: 16px; - } From ddbeb2c92e2de2b96ac7524acedde3b08f2cc276 Mon Sep 17 00:00:00 2001 From: Caleb Richelson Date: Thu, 23 Aug 2018 13:42:56 -0400 Subject: [PATCH 2/4] GH-339 Ghostery Hub Home View --- _locales/en/messages.json | 51 ++++++ app/hub/App.jsx | 2 +- app/hub/Views/HomeView/HomeView.jsx | 165 +++++++++++++----- app/hub/Views/HomeView/HomeView.scss | 123 ++++++++++++- app/hub/Views/HomeView/HomeViewActions.js | 31 +++- app/hub/Views/HomeView/HomeViewConstants.js | 4 +- app/hub/Views/HomeView/HomeViewContainer.jsx | 56 +++++- app/hub/Views/HomeView/HomeViewReducer.js | 28 ++- app/hub/Views/HomeView/index.js | 7 +- app/hub/Views/SetupView/SetupViewConstants.js | 3 + .../Views/SetupView/SetupViewContainer.jsx | 17 +- .../SetupDoneView/SetupDoneViewActions.js | 28 +++ .../SetupDoneView/SetupDoneViewContainer.jsx | 6 +- .../__tests__/SetupDoneViewActions.test.js | 47 +++++ .../Views/SetupViews/SetupDoneView/index.js | 5 +- .../SideNavigationView/SideNavigationView.jsx | 18 +- .../SideNavigationView.scss | 3 + app/hub/Views/SideNavigationView/index.js | 16 ++ app/hub/Views/TutorialView/TutorialView.scss | 2 + .../TutorialView/TutorialViewConstants.js | 5 +- .../TutorialView/TutorialViewContainer.jsx | 9 +- app/hub/Views/TutorialView/index.js | 6 +- .../TutorialAntiSuiteViewActions.js | 28 +++ .../TutorialAntiSuiteViewContainer.jsx | 2 + .../TutorialAntiSuiteView/index.js | 6 +- .../TutorialBlockingView/index.js | 1 + .../TutorialViews/TutorialLayoutView/index.js | 1 + .../TutorialTrackerListView/index.js | 1 + .../TutorialViews/TutorialTrustView/index.js | 1 + .../TutorialViews/TutorialVideoView/index.js | 1 + app/hub/createStore.js | 2 +- .../ghosty-bubble-heart.svg} | 0 app/scss/_settings_hub.scss | 2 +- app/scss/hub.scss | 7 - app/scss/partials/_hub_svgs.scss | 17 ++ src/background.js | 25 +++ src/classes/ConfData.js | 2 + 37 files changed, 622 insertions(+), 106 deletions(-) create mode 100644 app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewActions.js create mode 100644 app/hub/Views/SetupViews/SetupDoneView/__tests__/SetupDoneViewActions.test.js create mode 100644 app/hub/Views/SideNavigationView/index.js create mode 100644 app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewActions.js rename app/images/hub/{ghosty-dialogue.svg => home/ghosty-bubble-heart.svg} (100%) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 9f4b5584d..c65f1e1c6 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -1596,6 +1596,57 @@ "hub_home_page_title": { "message": "Ghostery Hub - Home" }, + "hub_home_header_text": { + "message": "Ghostery is ready!" + }, + "hub_home_header_tagline": { + "message": "You are now protected with our default settings." + }, + "hub_home_header_tagline_2": { + "message": "Start Browsing!" + }, + "hub_home_header_checkbox_label": { + "message": "Share analytics and Human Web data to improve Ghostery’s performance. " + }, + "hub_home_header_checkbox_link": { + "message": "Learn More." + }, + "hub_home_subheader_optimize": { + "message": "Optimize your Ghostery experience" + }, + "hub_home_subheader_create_account": { + "message": "Create Account" + }, + "hub_home_feature_tutorial_title": { + "message": "Take a Tutorial" + }, + "hub_home_feature_tutorial_text": { + "message": "Walk through Ghostery's main features." + }, + "hub_home_feature_tutorial_button": { + "message": "Start" + }, + "hub_home_feature_tutorial_button_alt": { + "message": "Tutorial Complete" + }, + "hub_home_feature_setup_title": { + "message": "Customize Setup" + }, + "hub_home_feature_setup_text": { + "message": "Edit your settings and blocking preferences." + }, + "hub_home_feature_setup_button": { + "message": "Edit Setup" + }, + "hub_home_feature_setup_button_alt": { + "message": "Custom Setup Complete" + }, + "hub_home_feature_supporter_text": { + "message": "Become a Ghostery Supporter and unlock special features." + }, + "hub_home_feature_supporter_button": { + "message": "Become a Supporter" + }, "hub_setup_page_title": { "message": "Ghostery Hub - Setup" }, diff --git a/app/hub/App.jsx b/app/hub/App.jsx index 060d8c0a3..cee8caa14 100644 --- a/app/hub/App.jsx +++ b/app/hub/App.jsx @@ -14,7 +14,7 @@ */ import React, { Component } from 'react'; -import SideNavigation from './Views/SideNavigationView/SideNavigationView'; +import SideNavigation from './Views/SideNavigationView'; /** * @class Implements the container App for the Ghostery Hub diff --git a/app/hub/Views/HomeView/HomeView.jsx b/app/hub/Views/HomeView/HomeView.jsx index 41bae253a..33a20d4fc 100644 --- a/app/hub/Views/HomeView/HomeView.jsx +++ b/app/hub/Views/HomeView/HomeView.jsx @@ -9,59 +9,136 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 - * - * ToDo: Update this file. */ import React from 'react'; +import ClassNames from 'classnames'; +import PropTypes from 'prop-types'; +import { NavLink } from 'react-router-dom'; +import { ToggleCheckbox } from '../../../shared-components'; /** - * @class Implement the Home View for the Ghostery Hub + * A Functional React component for rendering the Home View + * @return {JSX} JSX for rendering the Home View of the Hub app * @memberof HubComponents */ -const HomeView = () => ( -
-
-
-
-
-
-

Ghostery is Ready!

-

you are now protected with the Ghostery recommended default settings.

- Start browsing! - -
-
-
-
- Optimze your ghostery experience -
- -
-
-
- tutorial -
-
- customize setup -
-
-
-
- become a ghostery support text -
-
- support button +const HomeView = (props) => { + const { + justInstalled, + setup_complete, + tutorial_complete, + enable_human_web, + changeHumanWeb, + account_text, + account_link, + } = props; + const tutorialFeatureClassNames = ClassNames('HomeView__onboardingFeature columns flex-container align-middle flex-dir-column', { + 'feature-tutorial-complete': tutorial_complete, + 'feature-tutorial': !tutorial_complete, + }); + const tutorialButtonClassNames = ClassNames('HomeView__featureButton button primary', { + hollow: tutorial_complete, + }); + const setupFeatureClassNames = ClassNames('HomeView__onboardingFeature columns flex-container align-middle flex-dir-column', { + 'feature-setup-complete': setup_complete, + 'feature-setup': !setup_complete, + }); + const setupButtonClassNames = ClassNames('HomeView__featureButton button primary', { + hollow: setup_complete, + }); + + return ( +
+
+
+ +
+

+ {t('hub_home_header_text')} +

+ {justInstalled && ( +
+ {t('hub_home_header_tagline')} +
+ )} +
+ {t('hub_home_header_tagline_2')} +
+
+ +
+ {t('hub_home_header_checkbox_label')} + + {t('hub_home_header_checkbox_link')} + +
+
+
+
+
+
+ {t('hub_home_subheader_optimize')} +
+ + {account_text} + +
+
+
+
+
+ {t('hub_home_feature_tutorial_title')} +
+
+ {t('hub_home_feature_tutorial_text')} +
+ + {tutorial_complete ? t('hub_home_feature_tutorial_button_alt') : t('hub_home_feature_tutorial_button')} + +
+
+
+
+
+ {t('hub_home_feature_setup_title')} +
+
+ {t('hub_home_feature_setup_text')} +
+ + {setup_complete ? t('hub_home_feature_setup_button_alt') : t('hub_home_feature_setup_button')} + +
+
+
+
+
+ {t('hub_home_feature_supporter_text')} +
+
+
+ + {t('hub_home_feature_supporter_button')} + +
+
+
-
-); + ); +}; +// PropTypes ensure we pass required props of the correct type +HomeView.propTypes = { + setup_complete: PropTypes.bool.isRequired, + tutorial_complete: PropTypes.bool.isRequired, + enable_human_web: PropTypes.bool.isRequired, + changeHumanWeb: PropTypes.func.isRequired, + account_text: PropTypes.string.isRequired, + account_link: PropTypes.string.isRequired, +}; export default HomeView; diff --git a/app/hub/Views/HomeView/HomeView.scss b/app/hub/Views/HomeView/HomeView.scss index 1e7f4a008..b94472f63 100644 --- a/app/hub/Views/HomeView/HomeView.scss +++ b/app/hub/Views/HomeView/HomeView.scss @@ -1,6 +1,121 @@ -.ghosty-dialogue { - height: 156px; - background-image: url('../images/hub/ghosty-dialogue.svg'); +/** + * Home View Sass + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +// Home View +.HomeView { + padding-top: 45px; + padding-bottom: 25px; + color: #4a4a4a; +} +.HomeView--bolded { + font-weight: 700; +} +.HomeView__header img { + max-width: 156px; + margin-right: 23px; +} +.HomeView__header h1 { + color: #4a4a4a; + margin-bottom: 19px; +} +.HomeView__headerTagline { + font-size: 20px; + line-height: 38px; + color: #4a4a4a; +} +.HomeView__supportContainer { + margin-top: 12px; + margin-left: -12px; +} +.HomeView__subHeader { + margin-top: 12px; + font-size: 16px; + font-weight: 500; + line-height: 32px; +} +.HomeView__subHeader a { + text-decoration: underline; +} +.HomeView__onboarding { + margin-top: 7px; + padding: 27px 12px 30px; + border-radius: 4px; + background-color: #f0f3f4; +} +.HomeView__onboardingFeature { + margin: 0 8px; + padding: 0 36px; +} +.HomeView__onboardingFeatureDivider { + margin: 7px 0 4px; + width: 1px; + padding: 0; + background-color: #979797; +} +.HomeView__supporter { + margin-top: 22px; + padding: 22px 12px; + background-color: #f0f3f4; + border-radius: 4px; +} +.HomeView__supporterFeature { + padding: 0 36px; +} +.HomeView__featureIcon { + height: 50px; + width: 50px; + margin: 0 24px; background-repeat: no-repeat; - background-size: contain; + background-position: center center; +} +.HomeView__onboardingFeature.feature-tutorial .HomeView__featureIcon { + background-image: buildIconWand(#4a4a4a); +} +.HomeView__onboardingFeature.feature-tutorial-complete .HomeView__featureIcon { + width: 100px; + margin: 0 0 0 50px; + background-image: buildIconWandCheck(#4a4a4a); +} +.HomeView__onboardingFeature.feature-setup .HomeView__featureIcon { + background-image: buildIconClipboard(#4a4a4a); +} +.HomeView__onboardingFeature.feature-setup-complete .HomeView__featureIcon { + width: 100px; + margin: 0 0 0 50px; + background-image: buildIconClipboardCheck(#4a4a4a); +} +.HomeView__featureIcon.feature-supporter { + background-image: buildIconFlag(#4a4a4a); +} +.HomeView__featureTitle { + text-align: center; + font-size: 18px; + padding: 22px 0 10px; +} +.HomeView__featureText { + text-align: center; + font-size: 14px; + line-height: 27px; +} +.HomeView__featureButton { + margin: 0; + font-size: 14px; + font-weight: 700; + line-height: 1.3; + text-transform: uppercase; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.24), 0 0 2px 0 rgba(0, 0, 0, 0.12); +} +.HomeView__onboarding .HomeView__featureButton { + margin-top: 26px; + min-width: 130px; } diff --git a/app/hub/Views/HomeView/HomeViewActions.js b/app/hub/Views/HomeView/HomeViewActions.js index 3cb00b75f..150748103 100644 --- a/app/hub/Views/HomeView/HomeViewActions.js +++ b/app/hub/Views/HomeView/HomeViewActions.js @@ -10,11 +10,32 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import { TOGGLE_ANALYTICS } from './HomeViewConstants'; -export function toggleAnalytics(data) { - return { - type: TOGGLE_ANALYTICS, - data, +import { log, sendMessageInPromise } from '../../utils'; +import { GET_HOME_PROPS, SET_HUMAN_WEB } from './HomeViewConstants'; + +export function getHomeProps() { + return function (dispatch) { + return sendMessageInPromise(GET_HOME_PROPS).then((data) => { + dispatch({ + type: GET_HOME_PROPS, + data, + }); + }).catch((err) => { + log('homeView Action getHomeProps Error', err); + }); + }; +} + +export function setHumanWeb(actionData) { + return function (dispatch) { + return sendMessageInPromise(SET_HUMAN_WEB, actionData).then((data) => { + dispatch({ + type: SET_HUMAN_WEB, + data, + }); + }).catch((err) => { + log('homeView Action setHumanWeb Error', err); + }); }; } diff --git a/app/hub/Views/HomeView/HomeViewConstants.js b/app/hub/Views/HomeView/HomeViewConstants.js index a5e278371..458c93d53 100644 --- a/app/hub/Views/HomeView/HomeViewConstants.js +++ b/app/hub/Views/HomeView/HomeViewConstants.js @@ -11,4 +11,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -export const TOGGLE_ANALYTICS = 'TOGGLE_ANALYTICS'; +// Home View +export const GET_HOME_PROPS = 'GET_HOME_PROPS'; +export const SET_HUMAN_WEB = 'SET_HUMAN_WEB'; diff --git a/app/hub/Views/HomeView/HomeViewContainer.jsx b/app/hub/Views/HomeView/HomeViewContainer.jsx index e8984aa39..d131ed431 100644 --- a/app/hub/Views/HomeView/HomeViewContainer.jsx +++ b/app/hub/Views/HomeView/HomeViewContainer.jsx @@ -13,39 +13,87 @@ import React from 'react'; import PropTypes from 'prop-types'; - +import QueryString from 'query-string'; import HomeView from './HomeView'; /** - * @class Implement the Tutorial View Container for the Ghostery Hub + * @class Implement the Home View Container for the Ghostery Hub * @extends Component * @memberof HubContainers */ class HomeViewContainer extends React.Component { constructor(props) { super(props); + + const { justInstalled } = QueryString.parse(window.location.search); + this.state = { + justInstalled, + }; + const title = t('hub_home_page_title'); window.document.title = title; + + this.props.actions.getHomeProps(); + } + + /** + * Function to handle toggling Human Web Opt-In + */ + _handleToggleHumanWeb = () => { + const enable_human_web = !this.props.home.enable_human_web; + this.props.actions.setHumanWeb({ enable_human_web }); } /** * React's required render function. Returns JSX - * @return {JSX} JSX for rendering the Tutorial View of the Hub app + * @return {JSX} JSX for rendering the Home View of the Hub app */ render() { - return ; + // ToDo: Get these from action, reducer and props. Will be on this.props.home + // These are passed as props so we can the user's email and link to their account when they are signed in + const account_text = t('hub_home_subheader_create_account'); + const account_link = '/create-account'; + + const { justInstalled } = this.state; + const { + setup_complete, + tutorial_complete, + enable_human_web, + } = this.props.home; + const childProps = { + justInstalled, + setup_complete, + tutorial_complete, + enable_human_web, + changeHumanWeb: this._handleToggleHumanWeb, + account_text, + account_link, + }; + + return ; } } +// PropTypes ensure we pass required props of the correct type +// Note: isRequired is not needed when a prop has a default value HomeViewContainer.propTypes = { home: PropTypes.shape({ + setup_complete: PropTypes.bool, + tutorial_complete: PropTypes.bool, enable_human_web: PropTypes.bool, + account_text: PropTypes.string, + account_link: PropTypes.string, }), }; +// Default props used throughout the Setup flow HomeViewContainer.defaultProps = { home: { + setup_complete: false, + tutorial_complete: false, enable_human_web: false, + account_text: '', + account_link: '', }, }; diff --git a/app/hub/Views/HomeView/HomeViewReducer.js b/app/hub/Views/HomeView/HomeViewReducer.js index 802425b52..05a34d962 100644 --- a/app/hub/Views/HomeView/HomeViewReducer.js +++ b/app/hub/Views/HomeView/HomeViewReducer.js @@ -10,17 +10,35 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -import { TOGGLE_ANALYTICS } from './HomeViewConstants'; + +import { GET_HOME_PROPS, SET_HUMAN_WEB } from './HomeViewConstants'; const initialState = {}; function HomeViewReducer(state = initialState, action) { switch (action.type) { - case TOGGLE_ANALYTICS: { + case GET_HOME_PROPS: { + const { + setup_complete, + tutorial_complete, + enable_human_web, + account_text, + account_link, + } = action.data; + return Object.assign({}, state, { + home: Object.assign({}, state.home, { + setup_complete, + tutorial_complete, + enable_human_web, + account_text, + account_link, + }), + }); + } + case SET_HUMAN_WEB: { + const { enable_human_web } = action.data; return Object.assign({}, state, { - home: { - enable_human_web: action.data.enable_human_web - }, + home: Object.assign({}, state.home, { enable_human_web }), }); } diff --git a/app/hub/Views/HomeView/index.js b/app/hub/Views/HomeView/index.js index b8a2de841..3997c15b2 100644 --- a/app/hub/Views/HomeView/index.js +++ b/app/hub/Views/HomeView/index.js @@ -10,12 +10,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import * as actions from './HomeViewActions'; -import HomeViewReducer from './HomeViewReducer'; import HomeViewContainer from './HomeViewContainer'; +import HomeViewReducer from './HomeViewReducer'; +import * as HomeViewActions from './HomeViewActions'; /** * Map redux store state properties to the component's own properties. @@ -32,7 +33,7 @@ const mapStateToProps = state => Object.assign({}, state.home); * @memberof SetupContainers */ const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(Object.assign(actions), dispatch), + actions: bindActionCreators(Object.assign(HomeViewActions), dispatch), }); export const reducer = HomeViewReducer; diff --git a/app/hub/Views/SetupView/SetupViewConstants.js b/app/hub/Views/SetupView/SetupViewConstants.js index b81dbb44c..65ee03a3f 100644 --- a/app/hub/Views/SetupView/SetupViewConstants.js +++ b/app/hub/Views/SetupView/SetupViewConstants.js @@ -32,3 +32,6 @@ export const SET_GHOSTERY_REWARDS = 'SET_GHOSTERY_REWARDS'; // Setup Human Web export const SET_HUMAN_WEB = 'SET_HUMAN_WEB'; + +// Setup Done +export const SET_SETUP_COMPLETE = 'SET_SETUP_COMPLETE'; diff --git a/app/hub/Views/SetupView/SetupViewContainer.jsx b/app/hub/Views/SetupView/SetupViewContainer.jsx index 8d2a1cabc..5c1b30496 100644 --- a/app/hub/Views/SetupView/SetupViewContainer.jsx +++ b/app/hub/Views/SetupView/SetupViewContainer.jsx @@ -26,15 +26,21 @@ import SetupHumanWebView from '../SetupViews/SetupHumanWebView'; import SetupDoneView from '../SetupViews/SetupDoneView'; /** - * @class Implement the Setup Container View for the Ghostery Hub + * @class Implement the Setup View Container for the Ghostery Hub * @extends Component * @memberof HubContainers */ class SetupViewContainer extends React.Component { constructor(props) { super(props); - const title = t('hub_setup_page_title'); + this.state = { + sendMountActions: false, + showModal: false, + }; + + this.props.history.push('/setup/1'); + const title = t('hub_setup_page_title'); window.document.title = title; this.props.actions.initSetupProps(this.props.setup); @@ -50,13 +56,6 @@ class SetupViewContainer extends React.Component { this._setDefaultSettings(); } }); - - this.state = { - sendMountActions: false, - showModal: false, - }; - - this.props.history.push('/setup/1'); } /** diff --git a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewActions.js b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewActions.js new file mode 100644 index 000000000..4d7383305 --- /dev/null +++ b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewActions.js @@ -0,0 +1,28 @@ +/** + * Setup Done View Action creators + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import { log, sendMessageInPromise } from '../../../utils'; +import { SET_SETUP_COMPLETE } from '../../SetupView/SetupViewConstants'; + +export function setSetupComplete() { + return function (dispatch) { + return sendMessageInPromise(SET_SETUP_COMPLETE).then((data) => { + dispatch({ + type: SET_SETUP_COMPLETE, + data, + }); + }).catch((err) => { + log('setupDone Action setSetupComplete Error', err); + }); + }; +} diff --git a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx index b1f1779a6..8abe362bb 100644 --- a/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx +++ b/app/hub/Views/SetupViews/SetupDoneView/SetupDoneViewContainer.jsx @@ -28,7 +28,7 @@ class SetupDoneViewContainer extends Component { const title = t('hub_setup_page_title_done'); window.document.title = title; - const { index } = this.props; + const { index, sendMountActions } = this.props; this.props.actions.setSetupNavigation({ activeIndex: index, hrefPrev: `/setup/${index - 1}`, @@ -38,6 +38,10 @@ class SetupDoneViewContainer extends Component { textNext: t('hub_setup_nav_done'), textDone: false, }); + + if (sendMountActions) { + this.props.actions.setSetupComplete(); + } } /** diff --git a/app/hub/Views/SetupViews/SetupDoneView/__tests__/SetupDoneViewActions.test.js b/app/hub/Views/SetupViews/SetupDoneView/__tests__/SetupDoneViewActions.test.js new file mode 100644 index 000000000..aec94ca5c --- /dev/null +++ b/app/hub/Views/SetupViews/SetupDoneView/__tests__/SetupDoneViewActions.test.js @@ -0,0 +1,47 @@ +/** + * Test file for Setup Done View Action creators + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import configureStore from 'redux-mock-store'; +import thunk from 'redux-thunk'; +import * as utils from '../../../../utils'; +import * as SetupDoneViewActions from '../SetupDoneViewActions'; +import { SET_SETUP_COMPLETE } from '../../../SetupView/SetupViewConstants'; + +const middlewares = [thunk]; +const mockStore = configureStore(middlewares); + +const testData = { test: true }; +utils.sendMessageInPromise = jest.fn((name) => new Promise((resolve, reject) => { + switch (name) { + case SET_SETUP_COMPLETE: { + resolve(testData); + break; + } + default: resolve(message); + } +})); + +describe('app/hub/Views/SetupViews/SetupDoneView actions', () => { + test('setSetupComplete action should return correctly', () => { + const initialState = {}; + const store = mockStore(initialState); + + const data = testData; + const expectedPayload = { data, type: SET_SETUP_COMPLETE }; + + return store.dispatch(SetupDoneViewActions.setSetupComplete()).then(() => { + const actions = store.getActions(); + expect(actions).toEqual([expectedPayload]); + }); + }); +}); diff --git a/app/hub/Views/SetupViews/SetupDoneView/index.js b/app/hub/Views/SetupViews/SetupDoneView/index.js index fa38134c1..70eab435b 100644 --- a/app/hub/Views/SetupViews/SetupDoneView/index.js +++ b/app/hub/Views/SetupViews/SetupDoneView/index.js @@ -15,6 +15,7 @@ import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import SetupDoneViewContainer from './SetupDoneViewContainer'; +import * as SetupDoneViewActions from './SetupDoneViewActions'; import { setSetupNavigation } from '../../SetupView/SetupViewActions'; /** @@ -32,7 +33,9 @@ const mapStateToProps = state => Object.assign({}, state.setup); * @memberof SetupContainers */ const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(Object.assign({}, { setSetupNavigation }), dispatch), + actions: bindActionCreators(Object.assign({}, SetupDoneViewActions, { + setSetupNavigation, + }), dispatch), }); export default connect(mapStateToProps, mapDispatchToProps)(SetupDoneViewContainer); diff --git a/app/hub/Views/SideNavigationView/SideNavigationView.jsx b/app/hub/Views/SideNavigationView/SideNavigationView.jsx index d3eacb0b6..9317d85b2 100644 --- a/app/hub/Views/SideNavigationView/SideNavigationView.jsx +++ b/app/hub/Views/SideNavigationView/SideNavigationView.jsx @@ -10,7 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 * - * ToDo: Update this file. + * ToDo: Add Proptypes (items) */ import React, { Component } from 'react'; @@ -51,22 +51,26 @@ class SideNavigationView extends Component { } /** - * A helper function for rendering a Side Navigation List Item - * @return {JSX} JSX for the Navigation Item + * Function to tell you if a route has nested routes + * @param {Object} item The route item in the Side Navigation + * @return {Boolean} Whether the route item has a nested route */ - - hasNestedRoutes(route) { + _hasNestedRoutes(item) { const parentRoutes = ['setup', 'tutorial']; - return parentRoutes.some(parentRoute => route.href.includes(parentRoute)); + return parentRoutes.some(parentRoute => item.href.includes(parentRoute)); } + /** + * Helper render function for rendering a Side Navigation List Item + * @return {JSX} JSX for the Navigation Item + */ _renderItem(item = {}, index) { switch (item.type) { case 'separator': return
; case 'link': return ( - +
{item.text}
diff --git a/app/hub/Views/SideNavigationView/SideNavigationView.scss b/app/hub/Views/SideNavigationView/SideNavigationView.scss index 18a7de0c7..185b41fca 100644 --- a/app/hub/Views/SideNavigationView/SideNavigationView.scss +++ b/app/hub/Views/SideNavigationView/SideNavigationView.scss @@ -9,6 +9,8 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 + * + * ToDo: Update to BEM [Block Element Modifier](https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) */ .App__leftNavigation { @@ -35,6 +37,7 @@ } } } + // Side Navigation .SideNavigation__container { background-color: $hoki; diff --git a/app/hub/Views/SideNavigationView/index.js b/app/hub/Views/SideNavigationView/index.js new file mode 100644 index 000000000..4d9f6d120 --- /dev/null +++ b/app/hub/Views/SideNavigationView/index.js @@ -0,0 +1,16 @@ +/** + * Point of entry index.js file for Side Navigation View + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import SideNavigationView from './SideNavigationView'; + +export default SideNavigationView; diff --git a/app/hub/Views/TutorialView/TutorialView.scss b/app/hub/Views/TutorialView/TutorialView.scss index 0011ae2c8..496763ecf 100644 --- a/app/hub/Views/TutorialView/TutorialView.scss +++ b/app/hub/Views/TutorialView/TutorialView.scss @@ -9,6 +9,8 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 + * + * ToDo: Update to BEM [Block Element Modifier](https://csswizardry.com/2013/01/mindbemding-getting-your-head-round-bem-syntax/) */ // purple rectangle outline diff --git a/app/hub/Views/TutorialView/TutorialViewConstants.js b/app/hub/Views/TutorialView/TutorialViewConstants.js index 47adcc798..5bfcc3799 100644 --- a/app/hub/Views/TutorialView/TutorialViewConstants.js +++ b/app/hub/Views/TutorialView/TutorialViewConstants.js @@ -11,6 +11,9 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0 */ +// Tutorial View export const INIT_TUTORIAL_PROPS = 'INIT_TUTORIAL_PROPS'; - export const SET_TUTORIAL_NAVIGATION = 'SET_TUTORIAL_NAVIGATION'; + +// Tutorial Done +export const SET_TUTORIAL_COMPLETE = 'SET_TUTORIAL_COMPLETE'; diff --git a/app/hub/Views/TutorialView/TutorialViewContainer.jsx b/app/hub/Views/TutorialView/TutorialViewContainer.jsx index b8d5668c9..af19b8f26 100644 --- a/app/hub/Views/TutorialView/TutorialViewContainer.jsx +++ b/app/hub/Views/TutorialView/TutorialViewContainer.jsx @@ -9,11 +9,12 @@ * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 + * + * ToDo: Add Proptypes */ import React from 'react'; import { withRouter } from 'react-router-dom'; - import TutorialView from './TutorialView'; // Component Views @@ -30,9 +31,6 @@ import TutorialAntiSuiteView from '../TutorialViews/TutorialAntiSuiteView'; * @memberof HubContainers */ class TutorialViewContainer extends React.Component { - /** - * Lifecycle Event - */ constructor(props) { super(props); const title = ''; @@ -46,7 +44,6 @@ class TutorialViewContainer extends React.Component { * @return {JSX} JSX for rendering the Tutorial View of the Hub app */ render() { - const activeIndex = +this.props.location.pathname.split('/').pop(); const steps = [ { index: 1, @@ -80,7 +77,7 @@ class TutorialViewContainer extends React.Component { }, ]; - return ; + return ; } } diff --git a/app/hub/Views/TutorialView/index.js b/app/hub/Views/TutorialView/index.js index f4ddb0dbb..6707b4f08 100644 --- a/app/hub/Views/TutorialView/index.js +++ b/app/hub/Views/TutorialView/index.js @@ -10,15 +10,13 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ -// import { connect } from 'react-redux'; -// import { bindActionCreators } from 'redux'; import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; -import * as actions from './TutorialViewActions'; import TutorialViewContainer from './TutorialViewContainer'; import TutorialViewReducer from './TutorialViewReducer'; +import * as TutorialViewActions from './TutorialViewActions'; /** * Map redux store state properties to the component's own properties. @@ -35,7 +33,7 @@ const mapStateToProps = state => Object.assign({}, state.tutorial); * @memberof SetupContainers */ const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(Object.assign(actions), dispatch), + actions: bindActionCreators(Object.assign(TutorialViewActions), dispatch), }); export const reducer = TutorialViewReducer; diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewActions.js b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewActions.js new file mode 100644 index 000000000..1b4ee12c3 --- /dev/null +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewActions.js @@ -0,0 +1,28 @@ +/** + * Tutorial Done View Action creators + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import { log, sendMessageInPromise } from '../../../utils'; +import { SET_TUTORIAL_COMPLETE } from '../../TutorialView/TutorialViewConstants'; + +export function setTutorialComplete() { + return function (dispatch) { + return sendMessageInPromise(SET_TUTORIAL_COMPLETE).then((data) => { + dispatch({ + type: SET_TUTORIAL_COMPLETE, + data, + }); + }).catch((err) => { + log('tutorialAntiSuite Action setTutorialComplete Error', err); + }); + }; +} diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx index 3f6ea2155..7fcd71aaa 100644 --- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx @@ -36,6 +36,8 @@ class TutorialAntiSuiteViewContainer extends Component { textNext: t('hub_setup_nav_done'), textDone: t('hub_setup_exit_flow'), }); + + this.props.actions.setTutorialComplete(); } render() { diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js index fe2e0d114..4570d30da 100644 --- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/index.js @@ -10,10 +10,12 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; import TutorialAntiSuiteViewContainer from './TutorialAntiSuiteViewContainer'; +import * as TutorialAntiSuiteViewActions from './TutorialAntiSuiteViewActions'; import { setTutorialNavigation } from '../../TutorialView/TutorialViewActions'; /** @@ -31,7 +33,9 @@ const mapStateToProps = state => Object.assign({}, state.tutorial); * @memberof TutorialContainers */ const mapDispatchToProps = dispatch => ({ - actions: bindActionCreators(Object.assign({}, { setTutorialNavigation }), dispatch), + actions: bindActionCreators(Object.assign({}, TutorialAntiSuiteViewActions, { + setTutorialNavigation, + }), dispatch), }); export default connect(mapStateToProps, mapDispatchToProps)(TutorialAntiSuiteViewContainer); diff --git a/app/hub/Views/TutorialViews/TutorialBlockingView/index.js b/app/hub/Views/TutorialViews/TutorialBlockingView/index.js index 2910d3795..0c58bef1f 100644 --- a/app/hub/Views/TutorialViews/TutorialBlockingView/index.js +++ b/app/hub/Views/TutorialViews/TutorialBlockingView/index.js @@ -10,6 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; diff --git a/app/hub/Views/TutorialViews/TutorialLayoutView/index.js b/app/hub/Views/TutorialViews/TutorialLayoutView/index.js index 0c3e0f4c0..2dc8e75f7 100644 --- a/app/hub/Views/TutorialViews/TutorialLayoutView/index.js +++ b/app/hub/Views/TutorialViews/TutorialLayoutView/index.js @@ -10,6 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; diff --git a/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js b/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js index ca422d9ee..95efc9645 100644 --- a/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js +++ b/app/hub/Views/TutorialViews/TutorialTrackerListView/index.js @@ -10,6 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; diff --git a/app/hub/Views/TutorialViews/TutorialTrustView/index.js b/app/hub/Views/TutorialViews/TutorialTrustView/index.js index 7be6989b0..95b4907d2 100644 --- a/app/hub/Views/TutorialViews/TutorialTrustView/index.js +++ b/app/hub/Views/TutorialViews/TutorialTrustView/index.js @@ -10,6 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; diff --git a/app/hub/Views/TutorialViews/TutorialVideoView/index.js b/app/hub/Views/TutorialViews/TutorialVideoView/index.js index f2dc50180..f59987b7f 100644 --- a/app/hub/Views/TutorialViews/TutorialVideoView/index.js +++ b/app/hub/Views/TutorialViews/TutorialVideoView/index.js @@ -10,6 +10,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0 */ + import { connect } from 'react-redux'; import { bindActionCreators } from 'redux'; diff --git a/app/hub/createStore.js b/app/hub/createStore.js index b6e56a1a2..92f9f0857 100644 --- a/app/hub/createStore.js +++ b/app/hub/createStore.js @@ -26,9 +26,9 @@ import { reducer as setup } from './Views/SetupView'; import { reducer as tutorial } from './Views/TutorialView'; const reducer = combineReducers({ + home, setup, tutorial, - home, }); /** diff --git a/app/images/hub/ghosty-dialogue.svg b/app/images/hub/home/ghosty-bubble-heart.svg similarity index 100% rename from app/images/hub/ghosty-dialogue.svg rename to app/images/hub/home/ghosty-bubble-heart.svg diff --git a/app/scss/_settings_hub.scss b/app/scss/_settings_hub.scss index 979967b02..d16357ee3 100644 --- a/app/scss/_settings_hub.scss +++ b/app/scss/_settings_hub.scss @@ -78,7 +78,7 @@ $foundation-palette: ( ); $body-background: $white; $body-font-color: $tundora; -$body-font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Roboto, Arial, sans-serif; +$body-font-family: Roboto, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; $body-antialiased: true; $global-margin: 1rem; $global-padding: 1rem; diff --git a/app/scss/hub.scss b/app/scss/hub.scss index f9e52af4a..716a42194 100644 --- a/app/scss/hub.scss +++ b/app/scss/hub.scss @@ -12,17 +12,11 @@ */ html, body, #root { - font-family: Roboto, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; height: 100%; width: 100%; margin: 0; } -<<<<<<< HEAD -// Foundation Overrides -h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { - font-family: Roboto, "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; -======= .App { height: 100%; width: 100%; @@ -33,7 +27,6 @@ h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 { .App__mainContent { height: 100%; flex-grow: 1; ->>>>>>> sidebar height - remove tmp scss } // Helper Classes diff --git a/app/scss/partials/_hub_svgs.scss b/app/scss/partials/_hub_svgs.scss index 775c5af19..00bf171ee 100644 --- a/app/scss/partials/_hub_svgs.scss +++ b/app/scss/partials/_hub_svgs.scss @@ -40,6 +40,23 @@ @return '%23' + str-slice('#{$color}', 2, -1); } +// Used in Home View +@function buildIconClipboard($stroke-color) { + @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2234%22%20height%3D%2242%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M7.953%2026.497h18.263V24.69H7.953v1.808zm-.001-3.72h18.262v-1.805H7.952v1.806zm0-3.712h18.262v-1.808H7.952v1.808zm.014-3.703h18.248V13.55H7.966v1.812zm3.623-11.118v1.83h10.972v-1.83h.373c2.269%200%204.537-.002%206.806%200%201.22%200%201.986.778%201.986%202.018v29.357c0%201.266-.757%202.035-2.004%202.035-8.429.002-16.856.002-25.286%200-1.223%200-1.992-.774-1.992-2.008-.002-9.787-.002-19.574%200-29.36%200-1.274.747-2.04%201.992-2.042%202.368-.002%204.734%200%207.153%200z%22%20fill%3D%22#DAF4FF%22/%3E%3Cpath%20d%3D%22M16.775%205.742c.976.008%201.811-.831%201.83-1.838.02-1.014-.816-1.89-1.81-1.897-.977-.007-1.813.832-1.83%201.839-.02%201.014.818%201.89%201.81%201.896zm-5.456%200H4.206c-1.24%200-1.982.773-1.982%202.056-.002%209.845-.002%2019.691%200%2029.537%200%201.241.763%202.022%201.982%202.022h25.15c1.24%200%201.992-.774%201.992-2.048V7.772c0-1.246-.76-2.03-1.973-2.03h-7.141v1.84H11.319v-1.84zm1.813-1.865c.067-2.229%201.74-3.626%203.426-3.74%201.734-.115%203.75%201.156%203.898%203.74h.387c2.886%200%205.774-.002%208.662%200%202.065.001%203.66%201.638%203.66%203.76%200%209.946.002%2019.89%200%2029.835%200%202.12-1.595%203.75-3.67%203.75H4.054c-2.048%200-3.65-1.643-3.65-3.736-.002-9.932-.002-19.865%200-29.797%200-2.205%201.567-3.81%203.72-3.812%202.863-.002%205.725%200%208.588%200h.419z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22/%3E%3Cpath%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20d%3D%22M7.655%2016.532h18.228V14.99H7.655zM7.655%2020.133h18.228V18.59H7.655zM7.655%2024.248h18.228v-1.543H7.655zM7.655%2027.849h18.228v-1.543H7.655z%22/%3E%3C/g%3E%3C/svg%3E'); +} +@function buildIconClipboardCheck($stroke-color) { + @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2281%22%20height%3D%2242%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M7.953%2026.497h18.263V24.69H7.953v1.808zm-.001-3.72h18.262v-1.805H7.952v1.806zm0-3.712h18.262v-1.808H7.952v1.808zm.014-3.703h18.248V13.55H7.966v1.812zm3.623-11.118v1.83h10.972v-1.83h.373c2.269%200%204.537-.002%206.806%200%201.22%200%201.986.778%201.986%202.018v29.357c0%201.266-.757%202.035-2.004%202.035-8.429.002-16.856.002-25.286%200-1.223%200-1.992-.774-1.992-2.008-.002-9.787-.002-19.574%200-29.36%200-1.274.747-2.04%201.992-2.042%202.368-.002%204.734%200%207.153%200z%22%20fill%3D%22#DAF4FF%22/%3E%3Cpath%20d%3D%22M16.775%205.742c.976.008%201.811-.831%201.83-1.838.02-1.014-.816-1.89-1.81-1.897-.977-.007-1.813.832-1.83%201.839-.02%201.014.818%201.89%201.81%201.896zm-5.456%200H4.206c-1.24%200-1.982.773-1.982%202.056-.002%209.845-.002%2019.691%200%2029.537%200%201.241.763%202.022%201.982%202.022h25.15c1.24%200%201.992-.774%201.992-2.048V7.772c0-1.246-.76-2.03-1.973-2.03h-7.141v1.84H11.319v-1.84zm1.813-1.865c.067-2.229%201.74-3.626%203.426-3.74%201.734-.115%203.75%201.156%203.898%203.74h.387c2.886%200%205.774-.002%208.662%200%202.065.001%203.66%201.638%203.66%203.76%200%209.946.002%2019.89%200%2029.835%200%202.12-1.595%203.75-3.67%203.75H4.054c-2.048%200-3.65-1.643-3.65-3.736-.002-9.932-.002-19.865%200-29.797%200-2.205%201.567-3.81%203.72-3.812%202.863-.002%205.725%200%208.588%200h.419z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22/%3E%3Cpath%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20d%3D%22M7.655%2016.532h18.228V14.99H7.655zM7.655%2020.133h18.228V18.59H7.655zM7.655%2024.248h18.228v-1.543H7.655zM7.655%2027.849h18.228v-1.543H7.655z%22/%3E%3Cpath%20d%3D%22M59.68%2035C54.443%2030.894%2049.256%2026.823%2044%2022.704c1.29-1.671%202.544-3.303%203.846-4.987l11.089%208.691C64.728%2019.951%2070.521%2013.501%2076.353%207L81%2011.233C73.883%2019.17%2066.8%2027.063%2059.68%2035%22%20fill%3D%22#1DAFED%22/%3E%3C/g%3E%3C/svg%3E'); +} +@function buildIconWand($stroke-color) { + @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2251%22%20height%3D%2245%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20fill%3D%22#DAF4FF%22%20d%3D%22M20%2021l6-6%2025%2023-6%207z%22/%3E%3Cpath%20d%3D%22M46.92%2038.41L17.702%2010.42c-.747-.715-1.653-1.022-2.613-1.022s-1.92.358-2.612%201.022l-.587.562a3.5%203.5%200%200%200%200%205.057l29.165%2027.94c.747.715%201.653%201.021%202.613%201.021s1.92-.358%202.612-1.022l.64-.51c1.44-1.43%201.44-3.678%200-5.057zM13.33%2012.413l.586-.562c.32-.306.693-.46%201.12-.46.426%200%20.853.154%201.12.46l4.052%203.882-2.826%202.707-4.052-3.882c-.587-.562-.587-1.532%200-2.145zm32.044%2029.574l-.586.562c-.32.307-.694.46-1.12.46-.427%200-.853-.153-1.12-.46l-23.62-22.627%202.826-2.708%2023.673%2022.68a1.423%201.423%200%200%201-.053%202.093zM26.5%206.896c2.08%200%203.733%202.196%203.733%204.086%200%20.562.48%201.021%201.066%201.021.586%200%201.066-.46%201.066-1.021%200-1.89%201.6-4.086%203.733-4.086.586%200%201.066-.46%201.066-1.022s-.48-1.022-1.066-1.022c-2.026%200-3.733-1.583-3.733-3.575%200-.562-.48-1.022-1.066-1.022-.587%200-1.066.46-1.066%201.022%200%201.94-1.653%203.575-3.733%203.575-.586%200-1.066.46-1.066%201.022s.48%201.022%201.066%201.022zm4.746-2.401c.426.562.96%201.073%201.546%201.43-.587.409-1.12.97-1.546%201.584-.427-.613-.96-1.175-1.547-1.584.64-.357%201.12-.868%201.547-1.43zm-15.57%2027.378c-1.332%200-2.452-1.073-2.452-2.35%200-.562-.48-1.021-1.066-1.021-.587%200-1.067.46-1.067%201.021%200%201.277-1.12%202.35-2.452%202.35-.587%200-1.067.46-1.067%201.021%200%20.562.48%201.022%201.067%201.022%201.28%200%202.452%201.328%202.452%202.707%200%20.562.48%201.022%201.067%201.022.586%200%201.066-.46%201.066-1.022%200-1.379%201.173-2.707%202.453-2.707.586%200%201.066-.46%201.066-1.022%200-.561-.48-1.021-1.066-1.021zm-3.518%201.788c-.214-.256-.427-.511-.694-.715.267-.205.48-.41.694-.613.213.255.426.46.693.613-.267.255-.533.46-.693.715zM9.277%205.414c.587%200%201.067-.46%201.067-1.021%200-.562-.48-1.022-1.067-1.022-1.333%200-2.452-1.072-2.452-2.35C6.825.46%206.345%200%205.758%200c-.586%200-1.066.46-1.066%201.022%200%201.277-1.12%202.35-2.453%202.35-.586%200-1.066.459-1.066%201.02%200%20.563.48%201.022%201.066%201.022%201.28%200%202.453%201.328%202.453%202.707%200%20.562.48%201.022%201.066%201.022.587%200%201.067-.46%201.067-1.022%200-1.379%201.173-2.707%202.452-2.707zM5.758%205.16c-.213-.255-.426-.51-.693-.715.267-.204.48-.409.693-.613.214.255.427.46.694.613-.267.255-.48.46-.694.715zm-.64%2017.162c0%20.562-.48%201.022-1.066%201.022-.213%200-.426.306-.426.613%200%20.562-.48%201.021-1.067%201.021-.586%200-1.066-.46-1.066-1.021%200-.307-.267-.613-.427-.613C.48%2023.343%200%2022.883%200%2022.32S.48%2021.3%201.066%2021.3a.412.412%200%200%200%20.427-.409c0-.562.48-1.022%201.066-1.022.587%200%201.067.46%201.067%201.022%200%20.255.213.409.426.409.64%200%201.067.46%201.067%201.021z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20fill-rule%3D%22nonzero%22/%3E%3C/g%3E%3C/svg%3E'); +} +@function buildIconWandCheck($stroke-color) { + @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2290%22%20height%3D%2245%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Cpath%20d%3D%22M68.68%2037C63.443%2032.894%2058.256%2028.823%2053%2024.704c1.29-1.671%202.544-3.303%203.846-4.987l11.089%208.691C73.728%2021.951%2079.521%2015.501%2085.353%209L90%2013.233C82.883%2021.17%2075.8%2029.063%2068.68%2037%22%20fill%3D%22#1DAFED%22/%3E%3Cpath%20fill%3D%22#DAF4FF%22%20d%3D%22M20%2021l6-6%2025%2023-6%207z%22/%3E%3Cpath%20d%3D%22M46.92%2038.41L17.702%2010.42c-.747-.715-1.653-1.022-2.613-1.022s-1.92.358-2.612%201.022l-.587.562a3.5%203.5%200%200%200%200%205.057l29.165%2027.94c.747.715%201.653%201.021%202.613%201.021s1.92-.358%202.612-1.022l.64-.51c1.44-1.43%201.44-3.678%200-5.057zM13.33%2012.413l.586-.562c.32-.306.693-.46%201.12-.46.426%200%20.853.154%201.12.46l4.052%203.882-2.826%202.707-4.052-3.882c-.587-.562-.587-1.532%200-2.145zm32.044%2029.574l-.586.562c-.32.307-.694.46-1.12.46-.427%200-.853-.153-1.12-.46l-23.62-22.627%202.826-2.708%2023.673%2022.68a1.423%201.423%200%200%201-.053%202.093zM26.5%206.896c2.08%200%203.733%202.196%203.733%204.086%200%20.562.48%201.021%201.066%201.021.586%200%201.066-.46%201.066-1.021%200-1.89%201.6-4.086%203.733-4.086.586%200%201.066-.46%201.066-1.022s-.48-1.022-1.066-1.022c-2.026%200-3.733-1.583-3.733-3.575%200-.562-.48-1.022-1.066-1.022-.587%200-1.066.46-1.066%201.022%200%201.94-1.653%203.575-3.733%203.575-.586%200-1.066.46-1.066%201.022s.48%201.022%201.066%201.022zm4.746-2.401c.426.562.96%201.073%201.546%201.43-.587.409-1.12.97-1.546%201.584-.427-.613-.96-1.175-1.547-1.584.64-.357%201.12-.868%201.547-1.43zm-15.57%2027.378c-1.332%200-2.452-1.073-2.452-2.35%200-.562-.48-1.021-1.066-1.021-.587%200-1.067.46-1.067%201.021%200%201.277-1.12%202.35-2.452%202.35-.587%200-1.067.46-1.067%201.021%200%20.562.48%201.022%201.067%201.022%201.28%200%202.452%201.328%202.452%202.707%200%20.562.48%201.022%201.067%201.022.586%200%201.066-.46%201.066-1.022%200-1.379%201.173-2.707%202.453-2.707.586%200%201.066-.46%201.066-1.022%200-.561-.48-1.021-1.066-1.021zm-3.518%201.788c-.214-.256-.427-.511-.694-.715.267-.205.48-.41.694-.613.213.255.426.46.693.613-.267.255-.533.46-.693.715zM9.277%205.414c.587%200%201.067-.46%201.067-1.021%200-.562-.48-1.022-1.067-1.022-1.333%200-2.452-1.072-2.452-2.35C6.825.46%206.345%200%205.758%200c-.586%200-1.066.46-1.066%201.022%200%201.277-1.12%202.35-2.453%202.35-.586%200-1.066.459-1.066%201.02%200%20.563.48%201.022%201.066%201.022%201.28%200%202.453%201.328%202.453%202.707%200%20.562.48%201.022%201.066%201.022.587%200%201.067-.46%201.067-1.022%200-1.379%201.173-2.707%202.452-2.707zM5.758%205.16c-.213-.255-.426-.51-.693-.715.267-.204.48-.409.693-.613.214.255.427.46.694.613-.267.255-.48.46-.694.715zm-.64%2017.162c0%20.562-.48%201.022-1.066%201.022-.213%200-.426.306-.426.613%200%20.562-.48%201.021-1.067%201.021-.586%200-1.066-.46-1.066-1.021%200-.307-.267-.613-.427-.613C.48%2023.343%200%2022.883%200%2022.32S.48%2021.3%201.066%2021.3a.412.412%200%200%200%20.427-.409c0-.562.48-1.022%201.066-1.022.587%200%201.067.46%201.067%201.022%200%20.255.213.409.426.409.64%200%201.067.46%201.067%201.021z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20fill-rule%3D%22nonzero%22/%3E%3C/g%3E%3C/svg%3E'); +} +@function buildIconFlag($stroke-color) { + @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2252%22%20height%3D%2254%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cg%20fill-rule%3D%22nonzero%22%20fill%3D%22none%22%3E%3Cpath%20d%3D%22M21.71%2023.779c.975.796%209.19-.614%2016.256-6.778%205.392-4.702%209.754-4.641%2012.122-4.039-1.506-2.093-4.454-5.429-7.66-4.946a.623.623%200%200%201-.584-.238.63.63%200%200%201-.08-.63c.45-1.055%201.847-3.52%205.529-5.237A15.944%2015.944%200%200%200%2042.595.569c-4.576-.552-8.687%201.043-12.22%204.746-2.784%202.917-5.238%204.238-7.289%203.933a3.55%203.55%200%200%201-1.024-.323l2.693%2011.34a.632.632%200%200%201-.155.58.618.618%200%200%201-.568.182%2017.4%2017.4%200%200%200-3.03-.32c.432.72.868%201.797.707%203.072zm1.497-4.135L20.093%206.536c-1.335-.607-7.775-3.142-12.483%201.87l3.407%2014.343c1.415-1.202%205.576-4.066%2012.19-3.105z%22%20fill%3D%22#DAF4FF%22/%3E%3Cpath%20d%3D%22M3.187%202.805a2.833%202.833%200%200%201%203.41%202.108%202.855%202.855%200%200%201-1.275%203.08c.013.03.034.057.042.091l.596%202.506c5.836-5.443%2013.566-1.478%2013.646-1.436.16.084.275.233.317.41l.227.955c.13.213.656.962%201.71%201.11%201.122.16%203.103-.332%206.187-3.564%209.11-9.548%2019.517-3.064%2019.621-2.997a.628.628%200%200%201-.12%201.12c-3.21%201.173-4.823%202.985-5.575%204.156%204.895.302%208.653%206.93%208.823%207.233a.631.631%200%200%201-.116.765.618.618%200%200%201-.765.07c-.051-.034-5.21-3.257-12.564%203.155-5.675%204.95-12.59%207.236-16.002%207.236-.718%200-1.281-.1-1.646-.3-.492-.27-.734-.719-.663-1.232.195-1.42-.677-2.564-.966-2.9-5.107.397-7.861%203.199-8.005%203.349-.01.01-.024.014-.034.024l5.823%2024.515a.627.627%200%200%201-.606.772.625.625%200%200%201-.605-.481L4.16%208.407A2.84%202.84%200%200%201%201.093%206.24c-.362-1.527.577-3.068%202.094-3.434zm17.092%2024.592c.976.797%209.191-.614%2016.257-6.777%205.391-4.702%209.753-4.642%2012.122-4.039-1.507-2.093-4.454-5.43-7.66-4.946a.623.623%200%200%201-.585-.238.63.63%200%200%201-.079-.63c.45-1.055%201.847-3.521%205.528-5.238a15.944%2015.944%200%200%200-4.698-1.341c-4.575-.552-8.687%201.043-12.22%204.746-2.784%202.916-5.238%204.238-7.288%203.933a3.55%203.55%200%200%201-1.025-.323l2.694%2011.34a.632.632%200%200%201-.156.58.618.618%200%200%201-.568.182%2017.4%2017.4%200%200%200-3.03-.321c.433.72.868%201.797.708%203.072zm1.616-4.142L18.78%2010.147c-1.335-.608-7.775-3.143-12.483%201.87l3.407%2014.342c1.415-1.201%205.576-4.065%2012.19-3.104zM2.305%205.948A1.583%201.583%200%200%200%204.213%207.13a1.598%201.598%200%200%200%201.173-1.923%201.587%201.587%200%200%200-1.909-1.18%201.598%201.598%200%200%200-1.172%201.922z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20stroke%3D%22#{_url-friendly-color($stroke-color)}%22%20stroke-width%3D%221.166%22/%3E%3C/g%3E%3C/svg%3E'); +} + // Used in Stepped Navigation @function buildIconX($stroke-color) { @return url('data:image/svg+xml;charset%3dUS-ASCII,%3Csvg%20width%3D%2215%22%20height%3D%2215%22%20xmlns%3D%22http://www.w3.org/2000/svg%22%3E%3Cpath%20d%3D%22M10.078%207.5l4.386-4.386a1.824%201.824%200%200%200-2.578-2.58L7.5%204.922%203.114.534a1.824%201.824%200%201%200-2.58%202.58L4.92%207.5.534%2011.886a1.824%201.824%200%200%200%202.578%202.58L7.5%2010.078l4.386%204.386a1.824%201.824%200%201%200%202.58-2.58L10.078%207.5z%22%20fill%3D%22#{_url-friendly-color($stroke-color)}%22%20fill-rule%3D%22evenodd%22/%3E%3C/svg%3E'); diff --git a/src/background.js b/src/background.js index cf267b179..b9f7aaa87 100644 --- a/src/background.js +++ b/src/background.js @@ -489,6 +489,19 @@ function handleRewards(name, message, callback) { */ function handleGhosteryHub(name, message, callback) { switch (name) { + case 'GET_HOME_PROPS': { + const { + setup_complete, + tutorial_complete, + enable_human_web, + } = conf; + callback({ + setup_complete, + tutorial_complete, + enable_human_web, + }); + break; + } case 'GET_SETUP_SHOW_WARNING_OVERRIDE': { const { setup_show_warning_override } = conf; callback({ setup_show_warning_override }); @@ -580,6 +593,18 @@ function handleGhosteryHub(name, message, callback) { callback({ enable_human_web }); break; } + case 'SET_SETUP_COMPLETE': { + const setup_complete = true; + conf.setup_complete = setup_complete; + callback({ setup_complete }); + break; + } + case 'SET_TUTORIAL_COMPLETE': { + const tutorial_complete = true; + conf.tutorial_complete = tutorial_complete; + callback({ tutorial_complete }); + break; + } default: break; } } diff --git a/src/classes/ConfData.js b/src/classes/ConfData.js index 7a38562cb..4942eb78e 100644 --- a/src/classes/ConfData.js +++ b/src/classes/ConfData.js @@ -132,6 +132,8 @@ class ConfData { _initProperty('setup_show_warning_override', true); _initProperty('setup_path', 0); _initProperty('setup_block', 1); + _initProperty('setup_complete', false); + _initProperty('tutorial_complete', false); _initProperty('cliqz_import_state', 0); // Complex props From 77a1aea75ca6b07f205e8493c3245178472a453c Mon Sep 17 00:00:00 2001 From: Caleb Richelson Date: Wed, 29 Aug 2018 17:22:13 -0400 Subject: [PATCH 3/4] Minor fixes --- app/hub/Views/SetupView/SetupView.jsx | 46 +++++++++++-------- .../Views/SetupView/SetupViewContainer.jsx | 2 +- app/hub/Views/TutorialView/TutorialView.jsx | 44 ++++++++++-------- .../TutorialView/TutorialViewContainer.jsx | 17 +++++-- .../TutorialAntiSuiteViewContainer.jsx | 6 ++- 5 files changed, 71 insertions(+), 44 deletions(-) diff --git a/app/hub/Views/SetupView/SetupView.jsx b/app/hub/Views/SetupView/SetupView.jsx index 79ed1eefa..c9bfdba04 100644 --- a/app/hub/Views/SetupView/SetupView.jsx +++ b/app/hub/Views/SetupView/SetupView.jsx @@ -24,26 +24,33 @@ import SetupHeader from '../SetupViews/SetupHeader'; * @return {JSX} JSX for rendering the Setup View of the Hub app * @memberof HubComponents */ -const SetupView = props => ( -
-
- {props.steps.map(step => ( - ( -
- - -
- )} - /> - ))} -
+const SetupView = (props) => { + const { + steps, + sendMountActions, + } = props; + + return ( +
+
+ {steps.map(step => ( + ( +
+ + +
+ )} + /> + ))} +
- -
-); + +
+ ); +}; // PropTypes ensure we pass required props of the correct type SetupView.propTypes = { @@ -56,6 +63,7 @@ SetupView.propTypes = { titleImage: PropTypes.string.isRequired, }).isRequired, })).isRequired, + sendMountActions: PropTypes.bool.isRequired, }; export default SetupView; diff --git a/app/hub/Views/SetupView/SetupViewContainer.jsx b/app/hub/Views/SetupView/SetupViewContainer.jsx index 5c1b30496..e05610600 100644 --- a/app/hub/Views/SetupView/SetupViewContainer.jsx +++ b/app/hub/Views/SetupView/SetupViewContainer.jsx @@ -26,7 +26,7 @@ import SetupHumanWebView from '../SetupViews/SetupHumanWebView'; import SetupDoneView from '../SetupViews/SetupDoneView'; /** - * @class Implement the Setup View Container for the Ghostery Hub + * @class Implement the Setup View for the Ghostery Hub * @extends Component * @memberof HubContainers */ diff --git a/app/hub/Views/TutorialView/TutorialView.jsx b/app/hub/Views/TutorialView/TutorialView.jsx index f60a85a12..17f57a718 100644 --- a/app/hub/Views/TutorialView/TutorialView.jsx +++ b/app/hub/Views/TutorialView/TutorialView.jsx @@ -23,25 +23,32 @@ import TutorialNavigation from '../TutorialViews/TutorialNavigation'; * @return {JSX} JSX for rendering the Setup View of the Hub app * @memberof HubComponents */ -const TutorialView = props => ( -
-
- {props.steps.map(step => ( - ( -
- -
- )} - /> - ))} -
+const TutorialView = (props) => { + const { + steps, + sendMountActions, + } = this.props; + + return ( +
+
+ {steps.map(step => ( + ( +
+ +
+ )} + /> + ))} +
- -
-); + +
+ ); +}; // PropTypes ensure we pass required props of the correct type TutorialView.propTypes = { @@ -50,6 +57,7 @@ TutorialView.propTypes = { path: PropTypes.string.isRequired, bodyComponent: PropTypes.func.isRequired, })).isRequired, + sendMountActions: PropTypes.bool.isRequired, }; export default TutorialView; diff --git a/app/hub/Views/TutorialView/TutorialViewContainer.jsx b/app/hub/Views/TutorialView/TutorialViewContainer.jsx index af19b8f26..c0d9d590d 100644 --- a/app/hub/Views/TutorialView/TutorialViewContainer.jsx +++ b/app/hub/Views/TutorialView/TutorialViewContainer.jsx @@ -26,17 +26,25 @@ import TutorialTrustView from '../TutorialViews/TutorialTrustView'; import TutorialAntiSuiteView from '../TutorialViews/TutorialAntiSuiteView'; /** - * @class Implement the Tutorial View Container for the Ghostery Hub + * @class Implement the Tutorial View for the Ghostery Hub * @extends Component * @memberof HubContainers */ class TutorialViewContainer extends React.Component { constructor(props) { super(props); + this.state = { + sendMountActions: false, + }; + + this.props.history.push('/tutorial/1'); + const title = ''; window.document.title = title; - this.props.actions.initTutorialProps(this.props.tutorial); - this.props.history.push('/tutorial/1'); + + this.props.actions.initTutorialProps(this.props.tutorial).then(() => { + this.setState({ sendMountActions: true }); + }); } /** @@ -44,6 +52,7 @@ class TutorialViewContainer extends React.Component { * @return {JSX} JSX for rendering the Tutorial View of the Hub app */ render() { + const { sendMountActions } = this.state; const steps = [ { index: 1, @@ -77,7 +86,7 @@ class TutorialViewContainer extends React.Component { }, ]; - return ; + return ; } } diff --git a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx index 7fcd71aaa..7954899ee 100644 --- a/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx +++ b/app/hub/Views/TutorialViews/TutorialAntiSuiteView/TutorialAntiSuiteViewContainer.jsx @@ -26,7 +26,7 @@ class TutorialAntiSuiteViewContainer extends Component { super(props); // TODO call setTutorialNavigation action - const { index } = this.props; + const { index, sendMountActions } = this.props; this.props.actions.setTutorialNavigation({ activeIndex: index, hrefPrev: `/tutorial/${index - 1}`, @@ -37,7 +37,9 @@ class TutorialAntiSuiteViewContainer extends Component { textDone: t('hub_setup_exit_flow'), }); - this.props.actions.setTutorialComplete(); + if (sendMountActions) { + this.props.actions.setTutorialComplete(); + } } render() { From d1dd69e2ab11656a1fd6a16fe47b306628786ecb Mon Sep 17 00:00:00 2001 From: Felix Schmetz Date: Thu, 30 Aug 2018 11:43:25 -0400 Subject: [PATCH 4/4] Unit tests for HomeView --- app/hub/Views/HomeView/HomeView.jsx | 1 + .../HomeView/__tests__/HomeView.test.jsx | 93 +++++ .../__snapshots__/HomeView.test.jsx.snap | 336 ++++++++++++++++++ 3 files changed, 430 insertions(+) create mode 100644 app/hub/Views/HomeView/__tests__/HomeView.test.jsx create mode 100644 app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap diff --git a/app/hub/Views/HomeView/HomeView.jsx b/app/hub/Views/HomeView/HomeView.jsx index 33a20d4fc..584ca0d06 100644 --- a/app/hub/Views/HomeView/HomeView.jsx +++ b/app/hub/Views/HomeView/HomeView.jsx @@ -133,6 +133,7 @@ const HomeView = (props) => { // PropTypes ensure we pass required props of the correct type HomeView.propTypes = { + justInstalled: PropTypes.bool.isRequired, setup_complete: PropTypes.bool.isRequired, tutorial_complete: PropTypes.bool.isRequired, enable_human_web: PropTypes.bool.isRequired, diff --git a/app/hub/Views/HomeView/__tests__/HomeView.test.jsx b/app/hub/Views/HomeView/__tests__/HomeView.test.jsx new file mode 100644 index 000000000..af4286485 --- /dev/null +++ b/app/hub/Views/HomeView/__tests__/HomeView.test.jsx @@ -0,0 +1,93 @@ +/** + * Setup Anti-Suite View Test Component + * + * Ghostery Browser Extension + * https://www.ghostery.com/ + * + * Copyright 2018 Ghostery, Inc. All rights reserved. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0 + */ + +import React from 'react'; +import renderer from 'react-test-renderer'; +import { shallow } from 'enzyme'; +import HomeView from '../HomeView'; +import HomeViewActions from '../HomeViewActions'; +import { MemoryRouter } from 'react-router'; +import { ToggleCheckbox } from '../../../../shared-components'; + + +describe('app/hub/Views/HomeView component', () => { + describe('Snapshot tests with react-test-renderer', () => { + test('home view is rendered correctly: all true', () => { + const initialState = { + justInstalled: true, + setup_complete: true, + tutorial_complete: true, + enable_human_web: true, + changeHumanWeb: () => {}, + account_text: 'test username', + account_link: '/test/url', + }; + + const component = renderer.create( + + + + ).toJSON(); + expect(component).toMatchSnapshot(); + }); + + test('home view is rendered correctly: all false', () => { + const initialState = { + justInstalled: false, + setup_complete: false, + tutorial_complete: false, + enable_human_web: false, + changeHumanWeb: () => {}, + account_text: 'test username', + account_link: '/test/url', + }; + + const component = renderer.create( + + + ).toJSON(); + expect(component).toMatchSnapshot(); + }); + }); + + describe('Shallow snapshot tests rendered with Enzyme', () => { + test('the happy path of the component', () => { + const initialState = { + justInstalled: true, + setup_complete: false, + tutorial_complete: false, + enable_human_web: false, + changeHumanWeb: jest.fn(), + account_text: 'test username', + account_link: '/test/url', + }; + + const component = shallow(); + expect(component.find('.HomeView').length).toBe(1); + expect(component.find('.button').length).toBe(3); + expect(component.find('.HomeView__header').length).toBe(1); + expect(component.find('.HomeView__subHeader').length).toBe(1); + + expect(component.find('.HomeView__headerTagline').length).toBe(2); + component.setProps({ justInstalled: false }); + expect(component.find('.HomeView__headerTagline').length).toBe(1); + + expect(component.find('.HomeView__featureButton.hollow').length).toBe(0); + component.setProps({ tutorial_complete: true }); + expect(component.find('.HomeView__featureButton.hollow').length).toBe(1); + + component.setProps({ setup_complete: true }); + expect(component.find('.HomeView__featureButton.hollow').length).toBe(2); + }); + }); +}); diff --git a/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap b/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap new file mode 100644 index 000000000..123d25711 --- /dev/null +++ b/app/hub/Views/HomeView/__tests__/__snapshots__/HomeView.test.jsx.snap @@ -0,0 +1,336 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`app/hub/Views/HomeView component Snapshot tests with react-test-renderer home view is rendered correctly: all false 1`] = ` +
+
+
+ +
+

+ hub_home_header_text +

+
+ hub_home_header_tagline_2 +
+
+
+ + + +
+
+ + hub_home_header_checkbox_label + + + hub_home_header_checkbox_link + +
+
+
+
+
+
+ hub_home_subheader_optimize +
+ + test username + +
+
+
+
+
+ hub_home_feature_tutorial_title +
+
+ hub_home_feature_tutorial_text +
+ + hub_home_feature_tutorial_button + +
+
+
+
+
+ hub_home_feature_setup_title +
+
+ hub_home_feature_setup_text +
+ + hub_home_feature_setup_button + +
+
+
+
+
+ hub_home_feature_supporter_text +
+ +
+
+
+`; + +exports[`app/hub/Views/HomeView component Snapshot tests with react-test-renderer home view is rendered correctly: all true 1`] = ` +
+
+
+ +
+

+ hub_home_header_text +

+
+ hub_home_header_tagline +
+
+ hub_home_header_tagline_2 +
+
+
+ + + +
+
+ + hub_home_header_checkbox_label + + + hub_home_header_checkbox_link + +
+
+
+
+
+
+ hub_home_subheader_optimize +
+ + test username + +
+
+
+
+
+ hub_home_feature_tutorial_title +
+
+ hub_home_feature_tutorial_text +
+ + hub_home_feature_tutorial_button_alt + +
+
+
+
+
+ hub_home_feature_setup_title +
+
+ hub_home_feature_setup_text +
+ + hub_home_feature_setup_button_alt + +
+
+
+
+
+ hub_home_feature_supporter_text +
+ +
+
+
+`;