1
0
mirror of http://git.whoc.org.uk/git/password-manager.git synced 2024-11-14 08:09:02 +01:00

Added a few feature based on actual subscription options

This commit is contained in:
Giulio Cesare Solaroli 2015-01-21 18:29:08 +01:00
parent 334affd36d
commit 43b0239ab8
8 changed files with 173 additions and 36 deletions

View File

@ -33,6 +33,41 @@ Clipperz.PM.DataModel.User.AccountInfo = function(args) {
Clipperz.Base.extend(Clipperz.PM.DataModel.User.AccountInfo, Object, { Clipperz.Base.extend(Clipperz.PM.DataModel.User.AccountInfo, Object, {
'status': function () {
return this._attributes['currentSubscriptionType'];
},
'level': function () {
var result;
// -1.00 -> EARLY_ADOPTER
// 2.00 -> FRIEND
// 5.00 -> FAN
// 10.00 -> DEVOTEE
// 15.00 -> PATRON
if (this.status() == 'FRIEND') {
result = 1;
} else if (this.status() == 'FAN') {
result = 2;
} else if (this.status() == 'DEVOTEE') {
result = 3;
} else if (this.status() == 'PATRON') {
result = 4;
} else {
result = 0;
};
return result;
// return this._attributes['latestActiveThreshold'];
},
'isExpiring': function () {
return this._attributes['isExpiring'];
},
//............................................................................
'features': function () { 'features': function () {
return this._attributes['features']; return this._attributes['features'];
}, },
@ -48,6 +83,12 @@ Clipperz.Base.extend(Clipperz.PM.DataModel.User.AccountInfo, Object, {
}; };
}, },
'isExpired': function () {
return this._attributes['isExpired'];
},
//========================================================================= //=========================================================================
__syntaxFix__: "syntax fix" __syntaxFix__: "syntax fix"
}); });

View File

@ -29,7 +29,7 @@ Clipperz.PM.UI.Components.CardToolbar = React.createClass({
// 'style': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired, // 'style': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired,
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
'enableSidePanels': React.PropTypes.bool.isRequired, 'enableSidePanels': React.PropTypes.bool.isRequired,
'accountStatus': React.PropTypes.object.isRequired, 'accountInfo': React.PropTypes.object.isRequired,
'messageBox': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired,
'filter': React.PropTypes.object /*.isRequired */ 'filter': React.PropTypes.object /*.isRequired */
}, },
@ -99,7 +99,7 @@ Clipperz.PM.UI.Components.CardToolbar = React.createClass({
return React.DOM.div({className:'cardToolbar ' + this.props['style']}, [ return React.DOM.div({className:'cardToolbar ' + this.props['style']}, [
// React.DOM.div({className:'header'}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()), // React.DOM.div({className:'header'}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()),
React.DOM.header({}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()), React.DOM.header({}, this.props['enableSidePanels'] ? this.renderWithSidePanels() : this.renderWithoutSidePanels()),
Clipperz.PM.UI.Components.AccountStatus(this.props['accountStatus']), Clipperz.PM.UI.Components.AccountStatus(this.props['accountInfo']),
Clipperz.PM.UI.Components.MessageBox(this.props['messageBox']), Clipperz.PM.UI.Components.MessageBox(this.props['messageBox']),
]); ]);
} }

View File

@ -30,6 +30,7 @@ Clipperz.PM.UI.Components.Cards.List = React.createClass({
propTypes: { propTypes: {
'cards': React.PropTypes.array, 'cards': React.PropTypes.array,
'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired,
'selectedCard': React.PropTypes.object 'selectedCard': React.PropTypes.object
}, },
@ -62,7 +63,8 @@ Clipperz.PM.UI.Components.Cards.List = React.createClass({
var cards = this.props['cards'] ? this.props['cards'] : []; var cards = this.props['cards'] ? this.props['cards'] : [];
var classes = { var classes = {
'cardList': true, 'cardList': true,
'loadingCard': this.props['selectedCard'] && this.props['selectedCard']['_reference'] && this.props['selectedCard']['loading'] 'loadingCard': this.props['selectedCard'] && this.props['selectedCard']['_reference'] && this.props['selectedCard']['loading'],
'EXPIRED': this.props['featureSet'] == 'EXPIRED',
}; };
classes[this.props['style']] = true; classes[this.props['style']] = true;

View File

@ -26,7 +26,7 @@ Clipperz.Base.module('Clipperz.PM.UI.Components');
Clipperz.PM.UI.Components.ExpiredPanel = React.createClass({ Clipperz.PM.UI.Components.ExpiredPanel = React.createClass({
propTypes: { propTypes: {
// featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, // featureSet: React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired,
// 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired // 'level': React.PropTypes.oneOf(['hide', 'info', 'warning', 'error']).isRequired
}, },

View File

@ -28,13 +28,14 @@ Clipperz.PM.UI.Components.Pages.MainPage = React.createClass({
getDefaultProps: function () { getDefaultProps: function () {
return { return {
} featureSet: 'FULL'
};
}, },
propTypes: { propTypes: {
'messageBox': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired,
// 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']), 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired,
'accountStatus': React.PropTypes.object.isRequired, 'accountInfo': React.PropTypes.object.isRequired,
// 'mediaQueryStyle': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired, // 'mediaQueryStyle': React.PropTypes.oneOf(['extra-short', 'narrow', 'wide', 'extra-wide']).isRequired,
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
// 'cards': React.PropTypes.deferred.isRequired // 'cards': React.PropTypes.deferred.isRequired

View File

@ -35,9 +35,31 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({
MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'downloadOfflineCopy'); MochiKit.Signal.signal(Clipperz.Signal.NotificationCenter, 'downloadOfflineCopy');
}, },
propTypes: {
'accountInfo': React.PropTypes.object.isRequired,
},
getInitialState: function() {
return {
'account': false,
'subscription': false,
'data': false,
};
},
toggleState: function (section) {
return MochiKit.Base.bind(function () {
var newState = {};
newState[section] = !this.state[section];
this.setState(newState);
}, this);
},
//========================================================================= //=========================================================================
render: function () { render: function () {
//console.log("ExtraFeaturesPanel props", this.props);
var classes = { var classes = {
'panel': true, 'panel': true,
'right': true, 'right': true,
@ -53,32 +75,93 @@ Clipperz.PM.UI.Components.Panels.ExtraFeaturesPanel = React.createClass({
React.DOM.div({}, [ React.DOM.div({}, [
React.DOM.ul({}, [ React.DOM.ul({}, [
React.DOM.li({}, [ React.DOM.li({'className':this.state['account'] ? 'open' : 'closed'}, [
React.DOM.h1({}, "Account"), React.DOM.h1({'onClick':this.toggleState('account')}, "Account"),
React.DOM.ul({}, [
React.DOM.li({}, [
React.DOM.h2({}, "Passphrase"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "One Time Passwords"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "Preferences"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "Delete account"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
])
])
]), ]),
React.DOM.li({}, [ React.DOM.li({'className':this.state['subscription'] ? 'open' : 'closed'}, [
React.DOM.h1({}, "Data"), React.DOM.h1({'onClick':this.toggleState('subscription')}, "Subscription"),
React.DOM.ul({}, [
React.DOM.li({}, [
React.DOM.h2({}, "x1"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "x2"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "x3"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "x4"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
])
])
]),
React.DOM.li({'className':this.state['data'] ? 'open' : 'closed'}, [
React.DOM.h1({'onClick':this.toggleState('data')}, "Data"),
React.DOM.ul({}, [ React.DOM.ul({}, [
React.DOM.li({}, [ React.DOM.li({}, [
React.DOM.h2({}, "Offline copy"), React.DOM.h2({}, "Offline copy"),
React.DOM.div({}, [ React.DOM.div({}, [
React.DOM.p({}, "With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet."), React.DOM.p({}, "With just one click you can dump all your encrypted data from Clipperz servers to your hard disk and create a read-only offline version of Clipperz to be used when you are not connected to the Internet."),
React.DOM.a({'onClick':this.handleDownloadOfflineCopyLink}, "Download") React.DOM.a({'className':'button', 'onClick':this.handleDownloadOfflineCopyLink}, "Download")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "Import"),
React.DOM.div({}, [
React.DOM.p({}, "")
])
]),
React.DOM.li({}, [
React.DOM.h2({}, "Export"),
React.DOM.div({}, [
React.DOM.p({}, "")
]) ])
]), ]),
React.DOM.li({}, [ React.DOM.li({}, [
React.DOM.h2({}, "Sharing"), React.DOM.h2({}, "Sharing"),
]), React.DOM.div({}, [
React.DOM.li({}, [ React.DOM.p({}, "")
React.DOM.h2({}, "Import"), ])
]),
React.DOM.li({}, [
React.DOM.h2({}, "Export"),
]) ])
]) ])
]),
React.DOM.li({}, [
React.DOM.h1({}, "Tools"),
]) ])
]) ])
]) ])

View File

@ -30,16 +30,10 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({
propTypes: { propTypes: {
'messageBox': React.PropTypes.object.isRequired, 'messageBox': React.PropTypes.object.isRequired,
'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL']).isRequired, 'featureSet': React.PropTypes.oneOf(['FULL', 'EXPIRED', 'TRIAL', 'OFFLINE']).isRequired,
'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired, 'style': React.PropTypes.oneOf(Clipperz_PM_UI_availableStyles).isRequired,
}, },
getDefaultProps: function () {
return {
featureSet: 'FULL'
};
},
style: function () { style: function () {
return this.props['style']; return this.props['style'];
}, },
@ -66,7 +60,13 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({
}, },
renderCardFrame: function (firstColumnComponents, secondColumnComponents) { renderCardFrame: function (firstColumnComponents, secondColumnComponents) {
var addCardButton = React.DOM.div({'className': 'addCardButton', 'onClick':this.handleAddCardClick}, 'add card'); var addCardButton;
if ((this.props['featureSet'] != 'EXPIRED') && (this.props['featureSet'] != 'OFFLINE')) {
addCardButton = React.DOM.div({'className': 'addCardButton', 'onClick':this.handleAddCardClick}, 'add card');
} else {
addCardButton = null;
}
return React.DOM.div({'key':'cardContent', 'className':'cardContent'}, [ return React.DOM.div({'key':'cardContent', 'className':'cardContent'}, [
React.DOM.div({'className':'cardListColumn column'}, [addCardButton, firstColumnComponents]), React.DOM.div({'className':'cardListColumn column'}, [addCardButton, firstColumnComponents]),
@ -82,7 +82,8 @@ Clipperz.PM.UI.Components.Panels.MainPanel = React.createClass({
cardToolbarProps = MochiKit.Base.merge(this.props, { cardToolbarProps = MochiKit.Base.merge(this.props, {
'key': 'toolbar', 'key': 'toolbar',
'style': this.style(), 'style': this.style(),
'enableSidePanels': (this.props['featureSet'] != 'EXPIRED') // 'enableSidePanels': (this.props['featureSet'] != 'EXPIRED')
'enableSidePanels': true,
}); });
return Clipperz.PM.UI.Components.CardToolbar(cardToolbarProps); return Clipperz.PM.UI.Components.CardToolbar(cardToolbarProps);

View File

@ -581,6 +581,7 @@ console.log("THE BROWSER IS OFFLINE");
var fullFilterCriteria; var fullFilterCriteria;
var selectedCardReference = this._selectedCardInfo ? this._selectedCardInfo['reference'] : null; var selectedCardReference = this._selectedCardInfo ? this._selectedCardInfo['reference'] : null;
//console.log("updateSelectedCards - ACCOUNT INFO.featureSet", this.userAccountInfo()['featureSet']);
if (aFilter['type'] == 'ALL') { if (aFilter['type'] == 'ALL') {
filterCriteria = MochiKit.Base.operator.truth; filterCriteria = MochiKit.Base.operator.truth;
sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label'); sortCriteria = Clipperz.Base.caseInsensitiveKeyComparator('label');
@ -884,7 +885,7 @@ console.log("THE BROWSER IS OFFLINE");
level = 'HIDE'; level = 'HIDE';
//console.log("messageBox - this.user()", this.user()); //console.log("messageBox - this.user()", this.user());
if (this.user() != null && this.user().accountInfo() != null && this.user().accountInfo().featureSet() == 'EXPIRED') { if (this.userAccountInfo()['featureSet'] == 'EXPIRED') {
message = "Exprired subscription"; message = "Exprired subscription";
level = 'ERROR'; level = 'ERROR';
} }
@ -905,6 +906,7 @@ console.log("THE BROWSER IS OFFLINE");
'currentSubscriptionType', 'currentSubscriptionType',
'expirationDate', 'expirationDate',
'featureSet', 'featureSet',
'features',
'isExpired', 'isExpired',
'isExpiring', 'isExpiring',
'paymentVerificationPending' 'paymentVerificationPending'
@ -944,9 +946,10 @@ console.log("THE BROWSER IS OFFLINE");
} else if (aPageName == 'mainPage') { } else if (aPageName == 'mainPage') {
extraProperties = { extraProperties = {
'messageBox': this.messageBoxContent(), 'messageBox': this.messageBoxContent(),
'accountStatus': this.userAccountInfo(), 'accountInfo': this.userAccountInfo(),
'selectionPanelStatus': this.isSelectionPanelOpen() ? 'OPEN' : 'CLOSED', 'selectionPanelStatus': this.isSelectionPanelOpen() ? 'OPEN' : 'CLOSED',
'settingsPanelStatus': this.isSettingsPanelOpen() ? 'OPEN' : 'CLOSED', 'settingsPanelStatus': this.isSettingsPanelOpen() ? 'OPEN' : 'CLOSED',
'featureSet': this.userAccountInfo()['featureSet'],
// 'shouldIncludeArchivedCards': this.shouldIncludeArchivedCards(), // 'shouldIncludeArchivedCards': this.shouldIncludeArchivedCards(),
// 'cards': …, // 'cards': …,
// 'tags': …, // 'tags': …,
@ -1135,9 +1138,15 @@ console.log("THE BROWSER IS OFFLINE");
}, },
selectCard_handler: function (someInfo, shouldUpdateCardDetail) { selectCard_handler: function (someInfo, shouldUpdateCardDetail) {
this._selectedCardInfo = someInfo; if (this.userAccountInfo()['featureSet'] != 'EXPIRED') {
this.refreshSelectedCards(); this._selectedCardInfo = someInfo;
this.updateSelectedCard(someInfo, true, shouldUpdateCardDetail); this.refreshSelectedCards();
this.updateSelectedCard(someInfo, true, shouldUpdateCardDetail);
// # TODO: make the selected element visible;
// this may not always be the case, as selection can also be changed using keys.
// MochiKit.Visual.ScrollTo(MochiKit.DOM.getElement("xxx"));
}
}, },
refreshCardEditDetail_handler: function (aRecordReference) { refreshCardEditDetail_handler: function (aRecordReference) {