mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-24 08:04:11 +08:00
fix(trial): Move”days left” bar to the sidebar, new design
This commit is contained in:
parent
ebb5584e54
commit
1734e588b6
5 changed files with 114 additions and 143 deletions
BIN
internal_packages/notifications/assets/minichevron@2x.png
Normal file
BIN
internal_packages/notifications/assets/minichevron@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 329 B |
|
@ -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 />;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 trial
|
||||
<a className="learn-more" onClick={this._onMoreInfo}>
|
||||
Learn more about <span>Nylas Pro</span>
|
||||
</a>
|
||||
<button className="btn subscribe" onClick={this._onUpgrade}>
|
||||
{buildingUpgradeURL ? "Please Wait..." : "Subscribe"}
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
return <span />;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue