Skip to content

Commit

Permalink
feat: show guided tooltip to invite page on first run
Browse files Browse the repository at this point in the history
  • Loading branch information
Sean Yesmunt committed Jan 24, 2019
1 parent 3e1f3f1 commit 5e118e0
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 187 deletions.
7 changes: 5 additions & 2 deletions src/renderer/component/common/tooltip.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ type Props = {
icon?: boolean,
direction: string,
onComponent?: boolean, // extra padding to account for button/form field size
guided?: boolean, // should tooltip stay open, guide callbacks will close it manually
};

type State = {
Expand All @@ -18,6 +19,7 @@ type State = {
class ToolTip extends React.PureComponent<Props, State> {
static defaultProps = {
direction: 'bottom',
alwaysVisible: false,
};

constructor(props: Props) {
Expand Down Expand Up @@ -88,7 +90,7 @@ class ToolTip extends React.PureComponent<Props, State> {

render() {
const { direction } = this.state;
const { children, label, body, icon, onComponent } = this.props;
const { children, label, body, icon, onComponent, guided } = this.props;

const tooltipContent = children || label;
const bodyLength = body.length;
Expand All @@ -106,14 +108,15 @@ class ToolTip extends React.PureComponent<Props, State> {
'tooltip--bottom': direction === 'bottom',
'tooltip--left': direction === 'left',
'tooltip--on-component': onComponent,
'tooltip--guided-help': guided,
})}
>
{tooltipContent}
<span
ref={ref => {
this.tooltip = ref;
}}
className={classnames('tooltip__body', {
className={classnames('card tooltip__body', {
'tooltip__body--short': isShortDescription,
})}
>
Expand Down
87 changes: 51 additions & 36 deletions src/renderer/component/inviteList/view.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow
import * as ICONS from 'constants/icons';
import React from 'react';
import Native from 'native';
import Icon from 'component/common/icon';
import RewardLink from 'component/rewardLink';
import { rewards } from 'lbryinc';
Expand All @@ -22,50 +23,64 @@ class InviteList extends React.PureComponent<Props> {
return null;
}

if (!invitees.length) {
return (
<div className="yrbl-wrap">
<img
alt="Friendly gerbil"
className="subscriptions__gerbil"
src={Native.imagePath('gerbil-happy.png')}
/>
<div className="card__content">
<h2 className="card__title">{__('Some Invite Title')}</h2>
<p className="card__subtitle">
{__(
'LBRY is powered by the users, not some large company. Invite your friends here to help out.'
)}
</p>
</div>
</div>
);
}

return (
<section className="card card--section">
<header className="card__header">
<h2 className="card__title">{__('Invite History')}</h2>
</header>

<div className="card__content">
{invitees.length === 0 && (
<span className="empty">{__("You haven't invited anyone.")} </span>
)}
{invitees.length > 0 && (
<table className="table table--stretch">
<thead>
<tr>
<th>{__('Invitee Email')}</th>
<th className="text-center">{__('Invite Status')}</th>
<th className="text-center">{__('Reward')}</th>
<table className="table table--stretch">
<thead>
<tr>
<th>{__('Invitee Email')}</th>
<th className="text-center">{__('Invite Status')}</th>
<th className="text-center">{__('Reward')}</th>
</tr>
</thead>
<tbody>
{invitees.map(invitee => (
<tr key={invitee.email}>
<td>{invitee.email}</td>
<td className="text-center">
{invitee.invite_accepted ? (
<Icon icon={ICONS.COMPLETED} />
) : (
<span className="empty">{__('unused')}</span>
)}
</td>
<td className="text-center">
{invitee.invite_reward_claimed && <Icon icon={ICONS.COMPLETED} />}
{!invitee.invite_reward_claimed && invitee.invite_reward_claimable ? (
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
) : (
<span className="empty">{__('unclaimable')}</span>
)}
</td>
</tr>
</thead>
<tbody>
{invitees.map(invitee => (
<tr key={invitee.email}>
<td>{invitee.email}</td>
<td className="text-center">
{invitee.invite_accepted ? (
<Icon icon={ICONS.COMPLETED} />
) : (
<span className="empty">{__('unused')}</span>
)}
</td>
<td className="text-center">
{invitee.invite_reward_claimed ? (
<Icon icon={ICONS.COMPLETED} />
) : invitee.invite_reward_claimable ? (
<RewardLink label={__('claim')} reward_type={rewards.TYPE_REFERRAL} />
) : (
<span className="empty">{__('unclaimable')}</span>
)}
</td>
</tr>
))}
</tbody>
</table>
)}
))}
</tbody>
</table>

<div className="help">
{__(
Expand Down
4 changes: 2 additions & 2 deletions src/renderer/component/router/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { connect } from 'react-redux';
import { selectCurrentPage, selectCurrentParams } from 'lbry-redux';
import { selectCurrentPage, selectCurrentParams, doToast } from 'lbry-redux';
import { doOpenModal } from 'redux/actions/app';
import Router from './view';

Expand All @@ -10,5 +10,5 @@ const select = state => ({

export default connect(
select,
{ doOpenModal }
{ doOpenModal, doToast }
)(Router);
133 changes: 75 additions & 58 deletions src/renderer/component/sideBar/view.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@
import * as React from 'react';
import Button from 'component/button';
import classnames from 'classnames';
import Tooltip from 'component/common/tooltip';

type SideBarLink = {
label: string,
path: string,
active: boolean,
icon: ?string,
subLinks: Array<SideBarLink>,
guide: ?string,
};

type Props = {
Expand All @@ -19,71 +21,86 @@ type Props = {
unreadSubscriptionTotal: number,
};

const SideBar = (props: Props) => {
const { navLinks, unreadSubscriptionTotal } = props;
class SideBar extends React.PureComponent<Props> {
renderNavLink(navLink: SideBarLink) {
const { label, path, active, subLinks = [], icon, guide } = navLink;

return (
<nav className="navigation">
<div className="navigation__links">
{navLinks.primary.map(({ label, path, active, icon }) => (
<Button
icon={icon}
className={classnames('navigation__link', {
'navigation__link--active': active,
})}
key={path}
label={
path === '/subscriptions' && unreadSubscriptionTotal
? `${label} (${unreadSubscriptionTotal})`
: label
}
navigate={path}
/>
))}
const inner = (
<li
className={classnames('navigation__link', {
'navigation__link--active': active,
})}
key={label}
>
<Button icon={icon} label={label} navigate={path} />

<ul>
<li className="navigation__link navigation__link--title">Account</li>
{
// The sublinks should be animated on open close
// Removing it because the current implementation with CSSTransitionGroup
// was really slow and looked pretty bad. Possible fix is upgrading to v2
// Not sure if that has better performance
}
{!!subLinks.length &&
active && (
<ul key="0" className="navigation__link-items">
{subLinks.map(({ active: subLinkActive, label: subLabel, path: subPath }) => (
<li
className={classnames('navigation__link-item', {
'navigation__link-item--active': subLinkActive,
})}
key={subPath}
>
{subPath ? (
<Button label={subLabel} navigate={subPath} />
) : (
<span>{subLabel}</span>
)}
</li>
))}
</ul>
)}
</li>
);

{navLinks.secondary.map(({ label, path, active, subLinks = [], icon }) => (
<li
return guide ? (
<Tooltip key={guide} guided direction="right" body={guide}>
{inner}
</Tooltip>
) : (
inner
);
}

render() {
const { navLinks, unreadSubscriptionTotal } = this.props;

return (
<nav className="navigation">
<div className="navigation__links">
{navLinks.primary.map(({ label, path, active, icon }) => (
<Button
icon={icon}
className={classnames('navigation__link', {
'navigation__link--active': active,
})}
key={label}
>
<Button icon={icon} label={label} navigate={path} />

{
// The sublinks should be animated on open close
// Removing it because the current implementation with CSSTransitionGroup
// was really slow and looked pretty bad. Possible fix is upgrading to v2
// Not sure if that has better performance
key={path}
label={
path === '/subscriptions' && unreadSubscriptionTotal
? `${label} (${unreadSubscriptionTotal})`
: label
}
{!!subLinks.length &&
active && (
<ul key="0" className="navigation__link-items">
{subLinks.map(({ active: subLinkActive, label: subLabel, path: subPath }) => (
<li
className={classnames('navigation__link-item', {
'navigation__link-item--active': subLinkActive,
})}
key={subPath}
>
{subPath ? (
<Button label={subLabel} navigate={subPath} />
) : (
<span>{subLabel}</span>
)}
</li>
))}
</ul>
)}
</li>
navigate={path}
/>
))}
</ul>
</div>
</nav>
);
};

<ul>
<li className="navigation__link navigation__link--title">Account</li>
{navLinks.secondary.map(this.renderNavLink)}
</ul>
</div>
</nav>
);
}
}

export default SideBar;
20 changes: 20 additions & 0 deletions src/renderer/constants/pages.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
export const AUTH = 'auth';
export const BACKUP = 'backup';
export const CHANNEL = 'channel';
export const DISCOVER = 'discover';
export const DOWNLOADED = 'downloaded';
export const HELP = 'help';
export const HISTORY = 'history';
export const INVITE = 'invite';
export const PUBLISH = 'publish';
export const PUBLISHED = 'published';
export const GET_CREDITS = 'getcredits';
export const REPORT = 'report';
export const REWARDS = 'rewards';
export const SEND = 'send';
export const SETTINGS = 'settings';
export const SHOW = 'show';
export const WALLET = 'wallet';
export const SUBSCRIPTIONS = 'subscriptions';
export const SEARCH = 'search';
export const USER_HISTORY = 'user_history';
1 change: 1 addition & 0 deletions src/renderer/constants/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
export const CREDIT_REQUIRED_ACKNOWLEDGED = 'credit_required_acknowledged';
export const NEW_USER_ACKNOWLEDGED = 'welcome_acknowledged';
export const EMAIL_COLLECTION_ACKNOWLEDGED = 'email_collection_acknowledged';
export const INVITE_ACKNOWLEDGED = 'invite_acknowledged';
export const LANGUAGE = 'language';
export const SHOW_NSFW = 'showNsfw';
export const SHOW_UNAVAILABLE = 'showUnavailable';
Expand Down
2 changes: 1 addition & 1 deletion src/renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,7 @@ const init = () => {
<Provider store={store}>
<SplashScreen
authenticate={() => app.store.dispatch(doAuthenticate(pjson.version))}
onReadyToLaunch={onDaemonReady}
onReadyToLaunch={console.log('ready to launch') || onDaemonReady}
/>
</Provider>,
document.getElementById('app')
Expand Down
5 changes: 5 additions & 0 deletions src/renderer/page/invite/index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
import * as SETTINGS from 'constants/settings';
import { connect } from 'react-redux';
import {
doFetchInviteStatus,
selectUserInviteStatusFailed,
selectUserInviteStatusIsPending,
} from 'lbryinc';
import { makeSelectClientSetting } from 'redux/selectors/settings';
import { doSetClientSetting } from 'redux/actions/settings';
import InvitePage from './view';

const select = state => ({
isFailed: selectUserInviteStatusFailed(state),
isPending: selectUserInviteStatusIsPending(state),
inviteAcknowledged: makeSelectClientSetting(state)(SETTINGS.INVITE_ACKNOWLEDGED),
});

const perform = dispatch => ({
fetchInviteStatus: () => dispatch(doFetchInviteStatus()),
acknowledgeInivte: () => dispatch(doSetClientSetting(SETTINGS.INVITE_ACKNOWLEDGED, true)),
});

export default connect(
Expand Down

0 comments on commit 5e118e0

Please sign in to comment.