From 74bab48749783e7b7b287b62b406d1f33e13fb62 Mon Sep 17 00:00:00 2001 From: liamcardenas Date: Fri, 16 Mar 2018 11:22:19 -0700 Subject: [PATCH 1/4] Added api sub logging, sub modal, and immediate download initiation --- src/renderer/analytics.js | 22 ++++++++++++++++-- .../component/subscribeButton/index.js | 2 ++ .../component/subscribeButton/view.jsx | 9 ++++++-- src/renderer/constants/modal_types.js | 1 + .../modal/modalFirstSubscription/index.js | 10 ++++++++ .../modal/modalFirstSubscription/view.jsx | 23 +++++++++++++++++++ src/renderer/modal/modalRouter/view.jsx | 7 ++++-- src/renderer/redux/actions/content.js | 2 +- src/renderer/redux/actions/subscriptions.js | 13 +++++++++-- 9 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 src/renderer/modal/modalFirstSubscription/index.js create mode 100644 src/renderer/modal/modalFirstSubscription/view.jsx diff --git a/src/renderer/analytics.js b/src/renderer/analytics.js index 57d053fc9..f785b3906 100644 --- a/src/renderer/analytics.js +++ b/src/renderer/analytics.js @@ -2,6 +2,8 @@ import mixpanel from 'mixpanel-browser'; import Lbryio from 'lbryio'; import isDev from 'electron-is-dev'; +import type { Subscription } from 'redux/reducers/subscriptions'; + if (isDev) { mixpanel.init('691723e855cabb9d27a7a79002216967'); @@ -13,7 +15,9 @@ type Analytics = { track: (string, ?Object) => void, setUser: Object => void, toggle: (boolean, ?boolean) => void, - apiLog: (string, string, string) => void, + apiLogView: (string, string, string) => void, + apiLogSubscribe: (Subscription) => void, + apiLogUnsubscribe: (Subscription) => void, }; let analyticsEnabled: boolean = false; @@ -44,7 +48,7 @@ const analytics: Analytics = { } analyticsEnabled = enabled; }, - apiLog: (uri: string, outpoint: string, claimId: string): void => { + apiLogView: (uri: string, outpoint: string, claimId: string): void => { if (analyticsEnabled) { Lbryio.call('file', 'view', { uri, @@ -53,6 +57,20 @@ const analytics: Analytics = { }).catch(() => {}); } }, + apiLogSubscribe: (subscription: Subscription): void => { + if (analyticsEnabled) { + Lbryio.call('subscription', 'new', { + subscription + }).catch(() => {}); + } + }, + apiLogUnsubscribe: (subscription: Subscription): void => { + if (analyticsEnabled) { + Lbryio.call('subscription', 'delete', { + subscription + }).catch(() => {}); + } + }, }; export default analytics; diff --git a/src/renderer/component/subscribeButton/index.js b/src/renderer/component/subscribeButton/index.js index 2f5dceb30..6c93bbb65 100644 --- a/src/renderer/component/subscribeButton/index.js +++ b/src/renderer/component/subscribeButton/index.js @@ -1,5 +1,6 @@ import { connect } from 'react-redux'; import { doChannelSubscribe, doChannelUnsubscribe } from 'redux/actions/subscriptions'; +import { doOpenModal } from 'redux/actions/app'; import { selectSubscriptions } from 'redux/selectors/subscriptions'; import SubscribeButton from './view'; @@ -11,4 +12,5 @@ const select = (state, props) => ({ export default connect(select, { doChannelSubscribe, doChannelUnsubscribe, + doOpenModal, })(SubscribeButton); diff --git a/src/renderer/component/subscribeButton/view.jsx b/src/renderer/component/subscribeButton/view.jsx index 216b0bf72..819055eed 100644 --- a/src/renderer/component/subscribeButton/view.jsx +++ b/src/renderer/component/subscribeButton/view.jsx @@ -1,7 +1,8 @@ import React from 'react'; import Link from 'component/link'; +import * as modals from 'constants/modal_types'; -export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannelUnsubscribe }) => { +export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannelUnsubscribe, doOpenModal }) => { const isSubscribed = subscriptions.map(subscription => subscription.channelName).indexOf(channelName) !== -1; @@ -15,12 +16,16 @@ export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannel iconRight={isSubscribed ? '' : 'at'} button={isSubscribed ? 'alt' : 'primary'} label={subscriptionLabel} - onClick={() => + onClick={() => { + if(!subscriptions.length) { + doOpenModal(modals.FIRST_SUBSCRIPTION); + } subscriptionHandler({ channelName, uri, }) } + } /> ) : null; diff --git a/src/renderer/constants/modal_types.js b/src/renderer/constants/modal_types.js index a0272b708..0c2e03da1 100644 --- a/src/renderer/constants/modal_types.js +++ b/src/renderer/constants/modal_types.js @@ -16,3 +16,4 @@ export const TRANSACTION_FAILED = 'transaction_failed'; export const REWARD_APPROVAL_REQUIRED = 'reward_approval_required'; export const AFFIRM_PURCHASE = 'affirm_purchase'; export const CONFIRM_CLAIM_REVOKE = 'confirmClaimRevoke'; +export const FIRST_SUBSCRIPTION = 'firstSubscription'; diff --git a/src/renderer/modal/modalFirstSubscription/index.js b/src/renderer/modal/modalFirstSubscription/index.js new file mode 100644 index 000000000..6ae41be50 --- /dev/null +++ b/src/renderer/modal/modalFirstSubscription/index.js @@ -0,0 +1,10 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { doCloseModal } from 'redux/actions/app'; +import ModalFirstSubscription from './view'; + +const perform = dispatch => () => ({ + closeModal: () => dispatch(doCloseModal()), +}); + +export default connect(null, perform)(ModalFirstSubscription); diff --git a/src/renderer/modal/modalFirstSubscription/view.jsx b/src/renderer/modal/modalFirstSubscription/view.jsx new file mode 100644 index 000000000..d2e17c38c --- /dev/null +++ b/src/renderer/modal/modalFirstSubscription/view.jsx @@ -0,0 +1,23 @@ +import React from 'react'; +import { Modal } from 'modal/modal'; +import Link from 'component/link/index'; + +const ModalFirstSubscription = props => { + const { closeModal } = props; + + return ( + +
+

{__('Your first subscription!')}

+

+ {__('When you subscribe to a channel, you will automatically download, and be notified of, all of its new content.')} +

+
+ +
+
+
+ ); +}; + +export default ModalFirstSubscription; diff --git a/src/renderer/modal/modalRouter/view.jsx b/src/renderer/modal/modalRouter/view.jsx index 341883171..510d49b9d 100644 --- a/src/renderer/modal/modalRouter/view.jsx +++ b/src/renderer/modal/modalRouter/view.jsx @@ -14,8 +14,9 @@ import ModalTransactionFailed from 'modal/modalTransactionFailed'; import ModalFileTimeout from 'modal/modalFileTimeout'; import ModalAffirmPurchase from 'modal/modalAffirmPurchase'; import ModalRevokeClaim from 'modal/modalRevokeClaim'; -import ModalEmailCollection from '../modalEmailCollection'; -import ModalPhoneCollection from '../modalPhoneCollection'; +import ModalEmailCollection from 'modal/modalEmailCollection'; +import ModalPhoneCollection from 'modal/modalPhoneCollection'; +import ModalFirstSubscription from 'modal/modalFirstSubscription'; import * as modals from 'constants/modal_types'; class ModalRouter extends React.PureComponent { @@ -135,6 +136,8 @@ class ModalRouter extends React.PureComponent { return ; case modals.EMAIL_COLLECTION: return ; + case modals.FIRST_SUBSCRIPTION: + return ; default: return null; } diff --git a/src/renderer/redux/actions/content.js b/src/renderer/redux/actions/content.js index 5fd99c23e..146b9b6d5 100644 --- a/src/renderer/redux/actions/content.js +++ b/src/renderer/redux/actions/content.js @@ -228,7 +228,7 @@ export function doDownloadFile(uri, streamInfo) { return dispatch => { dispatch(doStartDownload(uri, streamInfo.outpoint)); - analytics.apiLog(uri, streamInfo.output, streamInfo.claim_id); + analytics.apiLogView(uri, streamInfo.output, streamInfo.claim_id); dispatch(doClaimEligiblePurchaseRewards()); }; diff --git a/src/renderer/redux/actions/subscriptions.js b/src/renderer/redux/actions/subscriptions.js index 8a390987b..02d2b5ea6 100644 --- a/src/renderer/redux/actions/subscriptions.js +++ b/src/renderer/redux/actions/subscriptions.js @@ -6,21 +6,30 @@ import Lbry from 'lbry'; import { doPurchaseUri } from 'redux/actions/content'; import { doNavigate } from 'redux/actions/navigation'; import { buildURI } from 'lbryURI'; +import analytics from 'analytics'; const CHECK_SUBSCRIPTIONS_INTERVAL = 60 * 60 * 1000; -export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) => +export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dispatch) => { dispatch({ type: ACTIONS.CHANNEL_SUBSCRIBE, data: subscription, }); -export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch) => + analytics.apiLogSubscribe(subscription); + + dispatch(doCheckSubscription(subscription, true)); +} + +export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch) => { dispatch({ type: ACTIONS.CHANNEL_UNSUBSCRIBE, data: subscription, }); + analytics.apiLogUnsubscribe(subscription); +} + export const doCheckSubscriptions = () => ( dispatch: Dispatch, getState: () => SubscriptionState From f2f316968bc1a04994a60914c218453bb73e9ddd Mon Sep 17 00:00:00 2001 From: liamcardenas Date: Fri, 16 Mar 2018 11:26:44 -0700 Subject: [PATCH 2/4] Fixed formatting issues --- src/renderer/analytics.js | 9 ++++----- src/renderer/component/subscribeButton/view.jsx | 16 +++++++++++----- .../modal/modalFirstSubscription/view.jsx | 6 ++++-- src/renderer/redux/actions/subscriptions.js | 4 ++-- 4 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/renderer/analytics.js b/src/renderer/analytics.js index f785b3906..2a03b7428 100644 --- a/src/renderer/analytics.js +++ b/src/renderer/analytics.js @@ -4,7 +4,6 @@ import Lbryio from 'lbryio'; import isDev from 'electron-is-dev'; import type { Subscription } from 'redux/reducers/subscriptions'; - if (isDev) { mixpanel.init('691723e855cabb9d27a7a79002216967'); } else { @@ -16,8 +15,8 @@ type Analytics = { setUser: Object => void, toggle: (boolean, ?boolean) => void, apiLogView: (string, string, string) => void, - apiLogSubscribe: (Subscription) => void, - apiLogUnsubscribe: (Subscription) => void, + apiLogSubscribe: Subscription => void, + apiLogUnsubscribe: Subscription => void, }; let analyticsEnabled: boolean = false; @@ -60,14 +59,14 @@ const analytics: Analytics = { apiLogSubscribe: (subscription: Subscription): void => { if (analyticsEnabled) { Lbryio.call('subscription', 'new', { - subscription + subscription, }).catch(() => {}); } }, apiLogUnsubscribe: (subscription: Subscription): void => { if (analyticsEnabled) { Lbryio.call('subscription', 'delete', { - subscription + subscription, }).catch(() => {}); } }, diff --git a/src/renderer/component/subscribeButton/view.jsx b/src/renderer/component/subscribeButton/view.jsx index 819055eed..bb0d0c146 100644 --- a/src/renderer/component/subscribeButton/view.jsx +++ b/src/renderer/component/subscribeButton/view.jsx @@ -2,7 +2,14 @@ import React from 'react'; import Link from 'component/link'; import * as modals from 'constants/modal_types'; -export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannelUnsubscribe, doOpenModal }) => { +export default ({ + channelName, + uri, + subscriptions, + doChannelSubscribe, + doChannelUnsubscribe, + doOpenModal, +}) => { const isSubscribed = subscriptions.map(subscription => subscription.channelName).indexOf(channelName) !== -1; @@ -17,15 +24,14 @@ export default ({ channelName, uri, subscriptions, doChannelSubscribe, doChannel button={isSubscribed ? 'alt' : 'primary'} label={subscriptionLabel} onClick={() => { - if(!subscriptions.length) { + if (!subscriptions.length) { doOpenModal(modals.FIRST_SUBSCRIPTION); } subscriptionHandler({ channelName, uri, - }) - } - } + }); + }} /> ) : null; diff --git a/src/renderer/modal/modalFirstSubscription/view.jsx b/src/renderer/modal/modalFirstSubscription/view.jsx index d2e17c38c..f489e6277 100644 --- a/src/renderer/modal/modalFirstSubscription/view.jsx +++ b/src/renderer/modal/modalFirstSubscription/view.jsx @@ -10,10 +10,12 @@ const ModalFirstSubscription = props => {

{__('Your first subscription!')}

- {__('When you subscribe to a channel, you will automatically download, and be notified of, all of its new content.')} + {__( + 'When you subscribe to a channel, you will automatically download, and be notified of, all of its new content.' + )}

- +
diff --git a/src/renderer/redux/actions/subscriptions.js b/src/renderer/redux/actions/subscriptions.js index 02d2b5ea6..58269ab40 100644 --- a/src/renderer/redux/actions/subscriptions.js +++ b/src/renderer/redux/actions/subscriptions.js @@ -19,7 +19,7 @@ export const doChannelSubscribe = (subscription: Subscription) => (dispatch: Dis analytics.apiLogSubscribe(subscription); dispatch(doCheckSubscription(subscription, true)); -} +}; export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: Dispatch) => { dispatch({ @@ -28,7 +28,7 @@ export const doChannelUnsubscribe = (subscription: Subscription) => (dispatch: D }); analytics.apiLogUnsubscribe(subscription); -} +}; export const doCheckSubscriptions = () => ( dispatch: Dispatch, From f74f4fbc229d9bc765b71a82afe3217d62037441 Mon Sep 17 00:00:00 2001 From: liamcardenas Date: Fri, 16 Mar 2018 12:04:22 -0700 Subject: [PATCH 3/4] Updated copy of subscriptions modal --- .../modal/modalFirstSubscription/index.js | 2 ++ .../modal/modalFirstSubscription/view.jsx | 28 +++++++++++++++---- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/renderer/modal/modalFirstSubscription/index.js b/src/renderer/modal/modalFirstSubscription/index.js index 6ae41be50..f507403d9 100644 --- a/src/renderer/modal/modalFirstSubscription/index.js +++ b/src/renderer/modal/modalFirstSubscription/index.js @@ -1,10 +1,12 @@ import React from 'react'; import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; +import { doNavigate } from 'redux/actions/navigation'; import ModalFirstSubscription from './view'; const perform = dispatch => () => ({ closeModal: () => dispatch(doCloseModal()), + navigate: path => dispatch(doNavigate(path)), }); export default connect(null, perform)(ModalFirstSubscription); diff --git a/src/renderer/modal/modalFirstSubscription/view.jsx b/src/renderer/modal/modalFirstSubscription/view.jsx index f489e6277..546819fbc 100644 --- a/src/renderer/modal/modalFirstSubscription/view.jsx +++ b/src/renderer/modal/modalFirstSubscription/view.jsx @@ -1,17 +1,35 @@ import React from 'react'; import { Modal } from 'modal/modal'; -import Link from 'component/link/index'; +import Link from 'component/link'; const ModalFirstSubscription = props => { - const { closeModal } = props; + const { closeModal, navigate } = props; return ( - +
-

{__('Your first subscription!')}

+

{__('Subscriptions 101')}

+

{__('You just subscribed to your first channel. Awesome!')}

+

{__('A few quick things to know:')}

+

+ {__('1) You can use the')}{' '} + { + navigate('/subscriptions'); + closeModal(); + }} + />{' '} + {__('to view content across all of your subscribed channels.')} +

{__( - 'When you subscribe to a channel, you will automatically download, and be notified of, all of its new content.' + '2) This app will automatically download new free content from channels you are subscribed to.' + )} +

+

+ {__( + '3) If we have your email address, we may send you notifications and rewards related to new content.' )}

From 32943b667ea09338d440852f59d939a9d34cf826 Mon Sep 17 00:00:00 2001 From: liamcardenas Date: Fri, 16 Mar 2018 12:07:31 -0700 Subject: [PATCH 4/4] Remove unused import --- src/renderer/modal/modalFirstSubscription/index.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/modal/modalFirstSubscription/index.js b/src/renderer/modal/modalFirstSubscription/index.js index f507403d9..6c669f79b 100644 --- a/src/renderer/modal/modalFirstSubscription/index.js +++ b/src/renderer/modal/modalFirstSubscription/index.js @@ -1,4 +1,3 @@ -import React from 'react'; import { connect } from 'react-redux'; import { doCloseModal } from 'redux/actions/app'; import { doNavigate } from 'redux/actions/navigation';