fix(trial): Move”days left” bar to the sidebar, new design

This commit is contained in:
Ben Gotow 2016-09-19 17:11:52 -07:00
parent ebb5584e54
commit 1734e588b6
5 changed files with 114 additions and 143 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 329 B

View file

@ -1,89 +0,0 @@
import {shell} from 'electron';
import {React, IdentityStore} from 'nylas-exports';
import {RetinaImg} from 'nylas-component-kit';
let NUM_TRIAL_DAYS = 30;
const HANDLE_WIDTH = 100;
export default class TrialRemainingHeader extends React.Component {
static displayName = "TrialRemainingHeader";
constructor(props) {
super(props)
this.state = this.getStateFromStores();
}
componentDidMount() {
this._unlisten = IdentityStore.listen(() =>
this.setState(this.getStateFromStores())
);
}
componentWillUnmount() {
if (this._unlisten) {
this._unlisten();
}
}
getStateFromStores = () => {
const daysRemaining = IdentityStore.daysUntilSubscriptionRequired();
if (daysRemaining > NUM_TRIAL_DAYS) {
NUM_TRIAL_DAYS = daysRemaining;
console.error("Unexpected number of days remaining in trial");
}
const inTrial = IdentityStore.subscriptionState() === IdentityStore.State.Trialing;
const daysIntoTrial = NUM_TRIAL_DAYS - daysRemaining;
const percentageIntoTrial = (NUM_TRIAL_DAYS - daysRemaining) / NUM_TRIAL_DAYS * 100;
return {
inTrial,
daysRemaining,
daysIntoTrial,
percentageIntoTrial,
handleStyle: {
left: `calc(${percentageIntoTrial}% - ${HANDLE_WIDTH / 2}px)`,
},
};
}
_onUpgrade = () => {
this.setState({buildingUpgradeURL: true});
const utm = {
source: "UpgradeBanner",
campaign: "TrialStillActive",
}
IdentityStore.fetchSingleSignOnURL('/payment', utm).then((url) => {
this.setState({buildingUpgradeURL: false});
shell.openExternal(url);
});
}
render() {
if (this.state.inTrial && this.state.daysRemaining !== 0) {
return (
<div className="trial-remaining-header notifications-sticky">
<div className="notifications-sticky-item">
<RetinaImg
className="icon"
name="nylas-identity-seafoam.png"
mode={RetinaImg.Mode.ContentPreserve}
stype={{height: "20px"}}
/>
Nylas N1 is in Trial Mode
<div className="trial-timer-wrapper">
<div className="trial-timer-progress" style={{width: `${this.state.percentageIntoTrial}%`}}></div>
<div className="trial-timer-handle" style={this.state.handleStyle}>
{NUM_TRIAL_DAYS - this.state.daysIntoTrial} Days Left
</div>
</div>
{this.state.daysIntoTrial}/{NUM_TRIAL_DAYS} Trial Days
<button className="upgrade-to-pro" onClick={this._onUpgrade}>
{this.state.buildingUpgradeURL ? "Please Wait..." : "Upgrade to Nylas Pro"}
</button>
</div>
</div>
)
}
return <span />;
}
}

View file

@ -6,14 +6,14 @@ import NotificationStore from './notifications-store';
import ConnectionStatusHeader from './headers/connection-status-header';
import AccountErrorHeader from './headers/account-error-header';
import NotificationsHeader from "./headers/notifications-header";
import TrialRemainingHeader from "./headers/trial-remaining-header";
import TrialRemainingBlock from "./sidebar/trial-remaining-block";
export function activate() {
ComponentRegistry.register(ActivitySidebar, {location: WorkspaceStore.Location.RootSidebar});
ComponentRegistry.register(NotificationsHeader, {location: WorkspaceStore.Sheet.Global.Header});
ComponentRegistry.register(ConnectionStatusHeader, {location: WorkspaceStore.Sheet.Global.Header});
ComponentRegistry.register(AccountErrorHeader, {location: WorkspaceStore.Sheet.Threads.Header});
ComponentRegistry.register(TrialRemainingHeader, {location: WorkspaceStore.Sheet.Global.Header});
ComponentRegistry.register(TrialRemainingBlock, {location: WorkspaceStore.Location.RootSidebar});
}
export function serialize() {}
@ -23,5 +23,5 @@ export function deactivate() {
ComponentRegistry.unregister(NotificationsHeader);
ComponentRegistry.unregister(ConnectionStatusHeader);
ComponentRegistry.unregister(AccountErrorHeader);
ComponentRegistry.unregister(TrialRemainingHeader);
ComponentRegistry.unregister(TrialRemainingBlock);
}

View file

@ -0,0 +1,67 @@
import {shell} from 'electron';
import {React, IdentityStore} from 'nylas-exports';
export default class TrialRemainingBlock extends React.Component {
static displayName = "TrialRemainingBlock";
constructor(props) {
super(props)
this.state = Object.assign({buildingUpgradeURL: false}, this.getStateFromStores());
}
componentDidMount() {
this._unlisten = IdentityStore.listen(() =>
this.setState(this.getStateFromStores())
);
}
componentWillUnmount() {
if (this._unlisten) {
this._unlisten();
}
}
getStateFromStores = () => {
return {
inTrial: (IdentityStore.subscriptionState() !== IdentityStore.State.Valid),
daysRemaining: IdentityStore.daysUntilSubscriptionRequired(),
};
}
_onUpgrade = () => {
this.setState({buildingUpgradeURL: true});
const utm = {
source: "UpgradeBanner",
campaign: "TrialStillActive",
}
IdentityStore.fetchSingleSignOnURL('/payment', utm).then((url) => {
this.setState({buildingUpgradeURL: false});
shell.openExternal(url);
});
}
_onMoreInfo = () => {
shell.openExternal(`https://www.nylas.com/?utm_medium=N1&utm_source=UpgradeBanner&utm_campaign=TrialMoreInfo`);
}
render() {
const {inTrial, daysRemaining, buildingUpgradeURL} = this.state;
const daysTerm = daysRemaining === 1 ? 'day' : 'days';
if (inTrial && (daysRemaining !== null)) {
return (
<div className="trial-remaining-block">
{`${daysRemaining} ${daysTerm} left in `}free&nbsp;trial
<a className="learn-more" onClick={this._onMoreInfo}>
Learn more about <span>Nylas&nbsp;Pro</span>
</a>
<button className="btn subscribe" onClick={this._onUpgrade}>
{buildingUpgradeURL ? "Please Wait..." : "Subscribe"}
</button>
</div>
)
}
return <span />;
}
}

View file

@ -1,59 +1,52 @@
.trial-remaining-header {
background-color: #f6f7f8;
box-shadow: 0 0 3px #999;
.trial-remaining-block {
text-align: center;
box-shadow: inset 0 0 1px 1px rgba(0,0,0,0.05);
display: flex;
flex-direction: column;
padding: 20px 20px;
.notifications-sticky-item {
color: black;
align-items: center;
padding: 5px;
font-size: 12px;
background: -webkit-linear-gradient(top, #41c190 0%, #41b78c 30%);
color: @text-color-inverse;
font-size: @font-size-large;
.learn-more {
border: 0;
color: @text-color-inverse-subtle;
font-size: @font-size-smaller;
padding-bottom:12px;
padding-top:2px;
span {
white-space: nowrap;
}
span:after {
content:'';
background: url(nylas://notifications/assets/minichevron@2x.png) top left no-repeat;
background-size: 4.5px 7px;
margin-left:3px;
display: inline-block;
width:4.5px;
height:7px;
vertical-align: baseline;
}
}
.icon {
border: solid #4b8e79 1px;
border-radius: 3px;
.learn-more:active {
color: @text-color-inverse-very-subtle;
}
.upgrade-to-pro {
margin: 0 10px;
.btn.subscribe {
border-radius: 5px;
color: white;
background-color: #30A797;
border: solid #30A797 1px;
color: @text-color-inverse;
background: -webkit-linear-gradient(top, fadeout(@text-color-inverse, 80%) 0%, fadeout(@text-color-inverse, 90%) 80%);
border: solid fade(@text-color-inverse, 60%) 1px;
box-shadow: 0 0 1px rgba(0,0,0,0.15);
padding: 0 12px;
cursor: pointer;
width: 160px;
margin: auto;
display: block;
max-width: 90%;
}
.btn.subscribe:active {
background: -webkit-linear-gradient(top, fadeout(@text-color, 80%) 0%, fadeout(@text-color, 90%) 80%);
}
}
@handleWidth: 100px;
@handleHeight: 30px;
.trial-timer-wrapper {
position: relative;
flex-grow: 1;
height: 2px;
background-color: #ccc;
border-radius: 2px;
margin: 0 ~"calc(5px + @{handleWidth}/2)";
}
.trial-timer-progress {
position: relative;
background-color: #30A797;
width: 50%;
height: 100%;
}
.trial-timer-handle {
background-color: #f6f7f8;
box-shadow: 0 1px 3px #ccc;
border: solid #ccc 1px;
border-radius: 15px;
text-align: center;
padding: 0 15px;
position: absolute;
top: ~"calc(50% - @{handleHeight}/2)";
color: #30A797;
width: @handleWidth;
height: @handleHeight;
}