From ea71fced95a6923926c92ada523840ebdbd0ef64 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:18:58 +0200 Subject: Replace invoices & subscription info with links to website --- src/api/PaymentApi.js | 8 -- src/api/server/ServerApi.js | 17 ---- .../settings/account/AccountDashboard.js | 107 +++++++-------------- src/config.js | 5 + src/containers/settings/AccountScreen.js | 69 +++++++------ src/environment.js | 14 ++- src/stores/PaymentStore.js | 17 ---- src/styles/badge.scss | 1 + src/styles/settings.scss | 13 ++- 9 files changed, 103 insertions(+), 148 deletions(-) diff --git a/src/api/PaymentApi.js b/src/api/PaymentApi.js index 3f6bb442e..7325151e9 100644 --- a/src/api/PaymentApi.js +++ b/src/api/PaymentApi.js @@ -11,12 +11,4 @@ export default class PaymentApi { getHostedPage(planId) { return this.server.getHostedPage(planId); } - - getDashboardUrl() { - return this.server.getPaymentDashboardUrl(); - } - - getOrders() { - return this.server.getSubscriptionOrders(); - } } diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index bafeef005..f6bc9c283 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js @@ -418,23 +418,6 @@ export default class ServerApi { return data; } - async getPaymentDashboardUrl() { - const request = await sendAuthRequest(`${API_URL}/me/billing`); - if (!request.ok) throw request; - const data = await request.json(); - debug('ServerApi::getPaymentDashboardUrl resolves', data); - return data; - } - - async getSubscriptionOrders() { - const request = await sendAuthRequest(`${API_URL}/me/subscription`); - if (!request.ok) throw request; - const data = await request.json(); - const orders = this._mapOrderModels(data); - debug('ServerApi::getSubscriptionOrders resolves', orders); - return orders; - } - // News async getLatestNews() { const url = `${API_URL}/news?platform=${os.platform()}&arch=${os.arch()}&version=${app.getVersion()}`; diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index 181b95c8c..ca8b9e1bd 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js @@ -3,12 +3,10 @@ import PropTypes from 'prop-types'; import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; import { defineMessages, intlShape } from 'react-intl'; import ReactTooltip from 'react-tooltip'; -import moment from 'moment'; import Loader from '../../ui/Loader'; import Button from '../../ui/Button'; import Infobox from '../../ui/Infobox'; -import Link from '../../ui/Link'; import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; const messages = defineMessages({ @@ -24,10 +22,6 @@ const messages = defineMessages({ id: 'settings.account.headlineUpgrade', defaultMessage: '!!!Upgrade your Account', }, - headlineInvoices: { - id: 'settings.account.headlineInvoices', - defaultMessage: '!!Invoices', - }, headlineDangerZone: { id: 'settings.account.headlineDangerZone', defaultMessage: '!!Danger Zone', @@ -48,6 +42,10 @@ const messages = defineMessages({ id: 'settings.account.account.editButton', defaultMessage: '!!!Edit Account', }, + invoicesButton: { + id: 'settings.account.headlineInvoices', + defaultMessage: '!!Invoices', + }, invoiceDownload: { id: 'settings.account.invoiceDownload', defaultMessage: '!!!Download', @@ -77,19 +75,17 @@ const messages = defineMessages({ export default @observer class AccountDashboard extends Component { static propTypes = { user: MobxPropTypes.observableObject.isRequired, - orders: MobxPropTypes.arrayOrObservableArray.isRequired, isLoading: PropTypes.bool.isRequired, - isLoadingOrdersInfo: PropTypes.bool.isRequired, isLoadingPlans: PropTypes.bool.isRequired, - isCreatingPaymentDashboardUrl: PropTypes.bool.isRequired, userInfoRequestFailed: PropTypes.bool.isRequired, retryUserInfoRequest: PropTypes.func.isRequired, - openDashboard: PropTypes.func.isRequired, - openExternalUrl: PropTypes.func.isRequired, onCloseSubscriptionWindow: PropTypes.func.isRequired, deleteAccount: PropTypes.func.isRequired, isLoadingDeleteAccount: PropTypes.bool.isRequired, isDeleteAccountSuccessful: PropTypes.bool.isRequired, + openEditAccount: PropTypes.func.isRequired, + openBilling: PropTypes.func.isRequired, + openInvoices: PropTypes.func.isRequired, }; static contextTypes = { @@ -99,12 +95,7 @@ export default @observer class AccountDashboard extends Component { render() { const { user, - orders, isLoading, - isCreatingPaymentDashboardUrl, - openDashboard, - openExternalUrl, - isLoadingOrdersInfo, isLoadingPlans, userInfoRequestFailed, retryUserInfoRequest, @@ -112,6 +103,9 @@ export default @observer class AccountDashboard extends Component { deleteAccount, isLoadingDeleteAccount, isDeleteAccountSuccessful, + openEditAccount, + openBilling, + openInvoices, } = this.props; const { intl } = this.context; @@ -161,68 +155,39 @@ export default @observer class AccountDashboard extends Component {

{`${user.firstname} ${user.lastname}`} + {user.isPremium && ( + <> + {' '} + {intl.formatMessage(messages.accountTypePremium)} + + )}

{user.organization && `${user.organization}, `} {user.email} -
- {user.isPremium && ( - {intl.formatMessage(messages.accountTypePremium)} - )} -
- - {intl.formatMessage(messages.accountEditButton)} - - {user.emailValidated} - - - )} - - {user.isSubscriptionOwner && ( - isLoadingOrdersInfo ? ( - - ) : ( -
- {orders.length > 0 && ( - -
-

{intl.formatMessage(messages.headlineSubscription)}

-
- {orders[0].name} - {orders[0].price} +
+
-
-
-

{intl.formatMessage(messages.headlineInvoices)}

- - - {orders.map(order => ( - - - - - ))} - -
- {moment(order.date).format('DD.MM.YYYY')} - - -
-
- - )} +
+
- ) + )} {!user.isPremium && ( diff --git a/src/config.js b/src/config.js index 479572edb..4423e61e9 100644 --- a/src/config.js +++ b/src/config.js @@ -12,6 +12,11 @@ export const CHECK_INTERVAL = ms('1h'); // How often should we perform checks export const LOCAL_API = 'http://localhost:3000'; export const DEV_API = 'https://dev.franzinfra.com'; export const LIVE_API = 'https://api.franzinfra.com'; + +export const LOCAL_API_WEBSITE = 'http://localhost:3333'; +export const DEV_API_WEBSITE = 'https://meetfranz.com'; +export const LIVE_API_WEBSITE = 'https://meetfranz.com'; + export const GA_ID = !isDevMode ? 'UA-74126766-10' : 'UA-74126766-12'; export const DEFAULT_APP_SETTINGS = { diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index ce1b9c333..0c837fab9 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js @@ -9,6 +9,7 @@ import AppStore from '../../stores/AppStore'; import AccountDashboard from '../../components/settings/account/AccountDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { WEBSITE } from '../../environment'; const { BrowserWindow } = remote; @@ -24,69 +25,77 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend onCloseWindow() { const { user, payment } = this.props.stores; user.getUserInfoRequest.invalidate({ immediately: true }); - payment.ordersDataRequest.invalidate({ immediately: true }); } reloadData() { const { user, payment } = this.props.stores; user.getUserInfoRequest.reload(); - payment.ordersDataRequest.reload(); payment.plansRequest.reload(); } async handlePaymentDashboard() { const { actions, stores } = this.props; - actions.payment.createDashboardUrl(); - - const dashboard = await stores.payment.createDashboardUrlRequest; - - if (dashboard.url) { - const paymentWindow = new BrowserWindow({ - title: '🔒 Franz Subscription Dashboard', - parent: remote.getCurrentWindow(), - modal: false, - width: 900, - minWidth: 600, - webPreferences: { - nodeIntegration: false, - }, - }); - paymentWindow.loadURL(dashboard.url); - - paymentWindow.on('closed', () => { - this.onCloseWindow(); - }); - } + // actions.payment.createDashboardUrl(); + + // const dashboard = await stores.payment.createDashboardUrlRequest; + + // if (dashboard.url) { + // const paymentWindow = new BrowserWindow({ + // title: '🔒 Franz Subscription Dashboard', + // parent: remote.getCurrentWindow(), + // modal: false, + // width: 900, + // minWidth: 600, + // webPreferences: { + // nodeIntegration: false, + // }, + // }); + // paymentWindow.loadURL(dashboard.url); + + // paymentWindow.on('closed', () => { + // this.onCloseWindow(); + // }); + // } + + const url = `${WEBSITE}/user/billing?token=${stores.user.authToken}&utm_source=app&utm_medium=edit_profile`; + + actions.app.openExternalUrl({ url }); + } + + handleWebsiteLink(route) { + const { actions, stores } = this.props; + + const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; + console.log(url); + + actions.app.openExternalUrl({ url }); } render() { const { user, payment } = this.props.stores; - const { openExternalUrl } = this.props.actions.app; const { user: userActions } = this.props.actions; const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; - const isLoadingOrdersInfo = payment.ordersDataRequest.isExecuting; const isLoadingPlans = payment.plansRequest.isExecuting; return ( this.reloadData()} - isCreatingPaymentDashboardUrl={payment.createDashboardUrlRequest.isExecuting} - openDashboard={price => this.handlePaymentDashboard(price)} - openExternalUrl={url => openExternalUrl({ url })} onCloseSubscriptionWindow={() => this.onCloseWindow()} deleteAccount={userActions.delete} isLoadingDeleteAccount={user.deleteAccountRequest.isExecuting} isDeleteAccountSuccessful={user.deleteAccountRequest.wasExecuted && !user.deleteAccountRequest.isError} + openEditAccount={() => this.handleWebsiteLink('/user/profile')} + openBilling={() => this.handleWebsiteLink('/user/billing')} + openInvoices={() => this.handleWebsiteLink('/user/invoices')} /> ); diff --git a/src/environment.js b/src/environment.js index 73b1c7ab2..68fa45173 100644 --- a/src/environment.js +++ b/src/environment.js @@ -1,6 +1,13 @@ import isDev from 'electron-is-dev'; -import { LIVE_API, DEV_API, LOCAL_API } from './config'; +import { + LIVE_API, + DEV_API, + LOCAL_API, + LOCAL_API_WEBSITE, + DEV_API_WEBSITE, + LIVE_API_WEBSITE, +} from './config'; export const isDevMode = isDev; export const useLiveAPI = process.env.LIVE_API; @@ -19,12 +26,17 @@ export const ctrlKey = isMac ? '⌘' : 'Ctrl'; export const cmdKey = isMac ? 'Cmd' : 'Ctrl'; let api; +let web; if (!isDevMode || (isDevMode && useLiveAPI)) { api = LIVE_API; + web = LIVE_API_WEBSITE; } else if (isDevMode && useLocalAPI) { api = LOCAL_API; + web = LOCAL_API_WEBSITE; } else { api = DEV_API; + web = DEV_API_WEBSITE; } export const API = api; +export const WEBSITE = web; diff --git a/src/stores/PaymentStore.js b/src/stores/PaymentStore.js index 4cabee194..d4de476c8 100644 --- a/src/stores/PaymentStore.js +++ b/src/stores/PaymentStore.js @@ -10,15 +10,10 @@ export default class PaymentStore extends Store { @observable createHostedPageRequest = new Request(this.api.payment, 'getHostedPage'); - @observable createDashboardUrlRequest = new Request(this.api.payment, 'getDashboardUrl'); - - @observable ordersDataRequest = new CachedRequest(this.api.payment, 'getOrders'); - constructor(...args) { super(...args); this.actions.payment.createHostedPage.listen(this._createHostedPage.bind(this)); - this.actions.payment.createDashboardUrl.listen(this._createDashboardUrl.bind(this)); } @computed get plan() { @@ -28,10 +23,6 @@ export default class PaymentStore extends Store { return this.plansRequest.execute().result || {}; } - @computed get orders() { - return this.ordersDataRequest.execute().result || []; - } - @action _createHostedPage({ planId }) { const request = this.createHostedPageRequest.execute(planId); @@ -39,12 +30,4 @@ export default class PaymentStore extends Store { return request; } - - @action _createDashboardUrl() { - const request = this.createDashboardUrlRequest.execute(); - - gaEvent('Payment', 'createDashboardUrl'); - - return request; - } } diff --git a/src/styles/badge.scss b/src/styles/badge.scss index f9fac039a..be3a1055d 100644 --- a/src/styles/badge.scss +++ b/src/styles/badge.scss @@ -19,6 +19,7 @@ display: inline-block; font-size: 14px; padding: 5px 10px; + letter-spacing: 0; &.badge--primary, &.badge--premium { diff --git a/src/styles/settings.scss b/src/styles/settings.scss index 750b6bedd..b286c6f1b 100644 --- a/src/styles/settings.scss +++ b/src/styles/settings.scss @@ -62,13 +62,18 @@ .account { .account__box { background: $dark-theme-gray-darker; } - .invoices { - td { border-bottom: 1px solid $dark-theme-gray-darker; } - .invoices__action button { color: $theme-brand-primary; } + .badge--premium { + margin-left: 10px; + } + + .manage-user-links { + margin-top: 20px; + display: flex; + justify-content: space-between; } } - .premium-info { + .premium-info { background: $dark-theme-gray-darker; border: 2px solid $theme-brand-primary; } -- cgit v1.2.3-70-g09d2 From 229c6017efbd0198747cba6e8997dc8ce4f9a7d4 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:32:16 +0200 Subject: Clean up --- src/containers/settings/AccountScreen.js | 36 +------------------------------- 1 file changed, 1 insertion(+), 35 deletions(-) diff --git a/src/containers/settings/AccountScreen.js b/src/containers/settings/AccountScreen.js index 0c837fab9..4ac7328c6 100644 --- a/src/containers/settings/AccountScreen.js +++ b/src/containers/settings/AccountScreen.js @@ -1,4 +1,3 @@ -import { remote } from 'electron'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; @@ -11,8 +10,6 @@ import AccountDashboard from '../../components/settings/account/AccountDashboard import ErrorBoundary from '../../components/util/ErrorBoundary'; import { WEBSITE } from '../../environment'; -const { BrowserWindow } = remote; - export default @inject('stores', 'actions') @observer class AccountScreen extends Component { componentWillMount() { const { @@ -23,7 +20,7 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend } onCloseWindow() { - const { user, payment } = this.props.stores; + const { user } = this.props.stores; user.getUserInfoRequest.invalidate({ immediately: true }); } @@ -34,36 +31,6 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend payment.plansRequest.reload(); } - async handlePaymentDashboard() { - const { actions, stores } = this.props; - - // actions.payment.createDashboardUrl(); - - // const dashboard = await stores.payment.createDashboardUrlRequest; - - // if (dashboard.url) { - // const paymentWindow = new BrowserWindow({ - // title: '🔒 Franz Subscription Dashboard', - // parent: remote.getCurrentWindow(), - // modal: false, - // width: 900, - // minWidth: 600, - // webPreferences: { - // nodeIntegration: false, - // }, - // }); - // paymentWindow.loadURL(dashboard.url); - - // paymentWindow.on('closed', () => { - // this.onCloseWindow(); - // }); - // } - - const url = `${WEBSITE}/user/billing?token=${stores.user.authToken}&utm_source=app&utm_medium=edit_profile`; - - actions.app.openExternalUrl({ url }); - } - handleWebsiteLink(route) { const { actions, stores } = this.props; @@ -84,7 +51,6 @@ export default @inject('stores', 'actions') @observer class AccountScreen extend Date: Mon, 8 Apr 2019 15:57:21 +0200 Subject: Update strings --- .../settings/account/AccountDashboard.json | 82 +++++++++++----------- 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/src/i18n/messages/src/components/settings/account/AccountDashboard.json b/src/i18n/messages/src/components/settings/account/AccountDashboard.json index 603950395..22eaf0381 100644 --- a/src/i18n/messages/src/components/settings/account/AccountDashboard.json +++ b/src/i18n/messages/src/components/settings/account/AccountDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 15, + "line": 13, "column": 12 }, "end": { - "line": 18, + "line": 16, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Your Subscription", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 19, + "line": 17, "column": 24 }, "end": { - "line": 22, + "line": 20, "column": 3 } }, @@ -30,24 +30,11 @@ "defaultMessage": "!!!Upgrade your Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 23, + "line": 21, "column": 19 }, "end": { - "line": 26, - "column": 3 - } - }, - { - "id": "settings.account.headlineInvoices", - "defaultMessage": "!!Invoices", - "file": "src/components/settings/account/AccountDashboard.js", - "start": { - "line": 27, - "column": 20 - }, - "end": { - "line": 30, + "line": 24, "column": 3 } }, @@ -56,11 +43,11 @@ "defaultMessage": "!!Danger Zone", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 31, + "line": 25, "column": 22 }, "end": { - "line": 34, + "line": 28, "column": 3 } }, @@ -69,11 +56,11 @@ "defaultMessage": "!!!Manage your subscription", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 35, + "line": 29, "column": 33 }, "end": { - "line": 38, + "line": 32, "column": 3 } }, @@ -82,11 +69,11 @@ "defaultMessage": "!!!Basic Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 39, + "line": 33, "column": 20 }, "end": { - "line": 42, + "line": 36, "column": 3 } }, @@ -95,11 +82,11 @@ "defaultMessage": "!!!Premium Supporter Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 43, + "line": 37, "column": 22 }, "end": { - "line": 46, + "line": 40, "column": 3 } }, @@ -108,11 +95,24 @@ "defaultMessage": "!!!Edit Account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 47, + "line": 41, "column": 21 }, "end": { - "line": 50, + "line": 44, + "column": 3 + } + }, + { + "id": "settings.account.headlineInvoices", + "defaultMessage": "!!Invoices", + "file": "src/components/settings/account/AccountDashboard.js", + "start": { + "line": 45, + "column": 18 + }, + "end": { + "line": 48, "column": 3 } }, @@ -121,11 +121,11 @@ "defaultMessage": "!!!Download", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 51, + "line": 49, "column": 19 }, "end": { - "line": 54, + "line": 52, "column": 3 } }, @@ -134,11 +134,11 @@ "defaultMessage": "!!!Could not load user information", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 55, + "line": 53, "column": 25 }, "end": { - "line": 58, + "line": 56, "column": 3 } }, @@ -147,11 +147,11 @@ "defaultMessage": "!!!Try again", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 59, + "line": 57, "column": 28 }, "end": { - "line": 62, + "line": 60, "column": 3 } }, @@ -160,11 +160,11 @@ "defaultMessage": "!!!Delete account", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 63, + "line": 61, "column": 17 }, "end": { - "line": 66, + "line": 64, "column": 3 } }, @@ -173,11 +173,11 @@ "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 67, + "line": 65, "column": 14 }, "end": { - "line": 70, + "line": 68, "column": 3 } }, @@ -186,11 +186,11 @@ "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", "file": "src/components/settings/account/AccountDashboard.js", "start": { - "line": 71, + "line": 69, "column": 19 }, "end": { - "line": 74, + "line": 72, "column": 3 } } -- cgit v1.2.3-70-g09d2 From c41bf73d129d2fba3ec23c1b7b463aaf9dc80dc6 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 15:57:32 +0200 Subject: Add new Team page in settings --- src/app.js | 2 + .../settings/navigation/SettingsNavigation.js | 11 ++ src/components/settings/team/TeamDashboard.js | 125 ++++++++++++++ .../ui/PremiumFeatureContainer/styles.js | 1 + src/containers/settings/TeamScreen.js | 63 +++++++ src/i18n/locales/defaultMessages.json | 192 +++++++++++++++------ src/i18n/locales/en-US.json | 7 + .../settings/navigation/SettingsNavigation.json | 25 ++- .../components/settings/team/TeamDashboard.json | 80 +++++++++ 9 files changed, 452 insertions(+), 54 deletions(-) create mode 100644 src/components/settings/team/TeamDashboard.js create mode 100644 src/containers/settings/TeamScreen.js create mode 100644 src/i18n/messages/src/components/settings/team/TeamDashboard.json diff --git a/src/app.js b/src/app.js index 6660feb46..96454779e 100644 --- a/src/app.js +++ b/src/app.js @@ -27,6 +27,7 @@ import RecipesScreen from './containers/settings/RecipesScreen'; import ServicesScreen from './containers/settings/ServicesScreen'; import EditServiceScreen from './containers/settings/EditServiceScreen'; import AccountScreen from './containers/settings/AccountScreen'; +import TeamScreen from './containers/settings/TeamScreen'; import EditUserScreen from './containers/settings/EditUserScreen'; import EditSettingsScreen from './containers/settings/EditSettingsScreen'; import InviteSettingsScreen from './containers/settings/InviteScreen'; @@ -77,6 +78,7 @@ window.addEventListener('load', () => { + diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js index 953f702f8..0be1a22ba 100644 --- a/src/components/settings/navigation/SettingsNavigation.js +++ b/src/components/settings/navigation/SettingsNavigation.js @@ -18,6 +18,10 @@ const messages = defineMessages({ id: 'settings.navigation.account', defaultMessage: '!!!Account', }, + team: { + id: 'settings.navigation.team', + defaultMessage: '!!!Manage Team', + }, settings: { id: 'settings.navigation.settings', defaultMessage: '!!!Settings', @@ -70,6 +74,13 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp > {intl.formatMessage(messages.account)} + + {intl.formatMessage(messages.team)} + ({ + cta: { + marginTop: 40, + }, +}); + + +export default @injectSheet(styles) @observer class TeamDashboard extends Component { + static propTypes = { + user: MobxPropTypes.observableObject.isRequired, + isLoading: PropTypes.bool.isRequired, + userInfoRequestFailed: PropTypes.bool.isRequired, + retryUserInfoRequest: PropTypes.func.isRequired, + openTeamManagement: PropTypes.func.isRequired, + upgradeAccount: PropTypes.func.isRequired, + classes: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { + user, + isLoading, + userInfoRequestFailed, + retryUserInfoRequest, + openTeamManagement, + upgradeAccount, + classes, + } = this.props; + const { intl } = this.context; + + return ( +
+
+ + {intl.formatMessage(messages.headline)} + +
+
+ {isLoading && ( + + )} + + {!isLoading && userInfoRequestFailed && ( + + {intl.formatMessage(messages.userInfoRequestFailed)} + + )} + + {!userInfoRequestFailed && ( + <> + {!isLoading && ( + <> + + <> +

{intl.formatMessage(messages.contentHeadline)}

+

{intl.formatMessage(messages.intro)}

+

{intl.formatMessage(messages.copy)}

+ {user.isSubscriptionOwner && ( +
+ +
+ ); + } +} diff --git a/src/components/ui/PremiumFeatureContainer/styles.js b/src/components/ui/PremiumFeatureContainer/styles.js index 81d6666c6..11cbfbb90 100644 --- a/src/components/ui/PremiumFeatureContainer/styles.js +++ b/src/components/ui/PremiumFeatureContainer/styles.js @@ -6,6 +6,7 @@ export default theme => ({ padding: 20, 'border-radius': theme.borderRadius, pointerEvents: 'none', + height: 'auto', }, titleContainer: { display: 'flex', diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js new file mode 100644 index 000000000..3a4b7ef77 --- /dev/null +++ b/src/containers/settings/TeamScreen.js @@ -0,0 +1,63 @@ +import { remote } from 'electron'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; +import { inject, observer } from 'mobx-react'; + +import PaymentStore from '../../stores/PaymentStore'; +import UserStore from '../../stores/UserStore'; +import AppStore from '../../stores/AppStore'; + +import TeamDashboard from '../../components/settings/team/TeamDashboard'; +import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { WEBSITE } from '../../environment'; + +const { BrowserWindow } = remote; + +export default @inject('stores', 'actions') @observer class TeamScreen extends Component { + handleWebsiteLink(route) { + const { actions, stores } = this.props; + + const url = `${WEBSITE}${route}?authToken=${stores.user.authToken}&utm_source=app&utm_medium=account_dashboard`; + console.log(url); + + actions.app.openExternalUrl({ url }); + } + + render() { + const { user } = this.props.stores; + + const isLoadingUserInfo = user.getUserInfoRequest.isExecuting; + + return ( + + this.reloadData()} + openTeamManagement={() => this.handleWebsiteLink('/user/team')} + /> + + ); + } +} + +TeamScreen.wrappedComponent.propTypes = { + stores: PropTypes.shape({ + user: PropTypes.instanceOf(UserStore).isRequired, + payment: PropTypes.instanceOf(PaymentStore).isRequired, + app: PropTypes.instanceOf(AppStore).isRequired, + }).isRequired, + actions: PropTypes.shape({ + payment: PropTypes.shape({ + createDashboardUrl: PropTypes.func.isRequired, + }).isRequired, + app: PropTypes.shape({ + openExternalUrl: PropTypes.func.isRequired, + }).isRequired, + user: PropTypes.shape({ + update: PropTypes.func.isRequired, + delete: PropTypes.func.isRequired, + }).isRequired, + }).isRequired, +}; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 0641c510c..3046f50ce 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -1076,195 +1076,195 @@ "defaultMessage": "!!!Account", "end": { "column": 3, - "line": 18 + "line": 16 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headline", "start": { "column": 12, - "line": 15 + "line": 13 } }, { "defaultMessage": "!!!Your Subscription", "end": { "column": 3, - "line": 22 + "line": 20 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineSubscription", "start": { "column": 24, - "line": 19 + "line": 17 } }, { "defaultMessage": "!!!Upgrade your Account", "end": { "column": 3, - "line": 26 + "line": 24 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineUpgrade", "start": { "column": 19, - "line": 23 - } - }, - { - "defaultMessage": "!!Invoices", - "end": { - "column": 3, - "line": 30 - }, - "file": "src/components/settings/account/AccountDashboard.js", - "id": "settings.account.headlineInvoices", - "start": { - "column": 20, - "line": 27 + "line": 21 } }, { "defaultMessage": "!!Danger Zone", "end": { "column": 3, - "line": 34 + "line": 28 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.headlineDangerZone", "start": { "column": 22, - "line": 31 + "line": 25 } }, { "defaultMessage": "!!!Manage your subscription", "end": { "column": 3, - "line": 38 + "line": 32 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.manageSubscription.label", "start": { "column": 33, - "line": 35 + "line": 29 } }, { "defaultMessage": "!!!Basic Account", "end": { "column": 3, - "line": 42 + "line": 36 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.accountType.basic", "start": { "column": 20, - "line": 39 + "line": 33 } }, { "defaultMessage": "!!!Premium Supporter Account", "end": { "column": 3, - "line": 46 + "line": 40 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.accountType.premium", "start": { "column": 22, - "line": 43 + "line": 37 } }, { "defaultMessage": "!!!Edit Account", "end": { "column": 3, - "line": 50 + "line": 44 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.account.editButton", "start": { "column": 21, - "line": 47 + "line": 41 + } + }, + { + "defaultMessage": "!!Invoices", + "end": { + "column": 3, + "line": 48 + }, + "file": "src/components/settings/account/AccountDashboard.js", + "id": "settings.account.headlineInvoices", + "start": { + "column": 18, + "line": 45 } }, { "defaultMessage": "!!!Download", "end": { "column": 3, - "line": 54 + "line": 52 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.invoiceDownload", "start": { "column": 19, - "line": 51 + "line": 49 } }, { "defaultMessage": "!!!Could not load user information", "end": { "column": 3, - "line": 58 + "line": 56 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.userInfoRequestFailed", "start": { "column": 25, - "line": 55 + "line": 53 } }, { "defaultMessage": "!!!Try again", "end": { "column": 3, - "line": 62 + "line": 60 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.tryReloadUserInfoRequest", "start": { "column": 28, - "line": 59 + "line": 57 } }, { "defaultMessage": "!!!Delete account", "end": { "column": 3, - "line": 66 + "line": 64 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteAccount", "start": { "column": 17, - "line": 63 + "line": 61 } }, { "defaultMessage": "!!!If you don't need your Franz account any longer, you can delete your account and all related data here.", "end": { "column": 3, - "line": 70 + "line": 68 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteInfo", "start": { "column": 14, - "line": 67 + "line": 65 } }, { "defaultMessage": "!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!", "end": { "column": 3, - "line": 74 + "line": 72 }, "file": "src/components/settings/account/AccountDashboard.js", "id": "settings.account.deleteEmailSent", "start": { "column": 19, - "line": 71 + "line": 69 } } ], @@ -1312,42 +1312,55 @@ } }, { - "defaultMessage": "!!!Settings", + "defaultMessage": "!!!Manage Team", "end": { "column": 3, "line": 24 }, "file": "src/components/settings/navigation/SettingsNavigation.js", + "id": "settings.navigation.team", + "start": { + "column": 8, + "line": 21 + } + }, + { + "defaultMessage": "!!!Settings", + "end": { + "column": 3, + "line": 28 + }, + "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.settings", "start": { "column": 12, - "line": 21 + "line": 25 } }, { "defaultMessage": "!!!Invite Friends", "end": { "column": 3, - "line": 28 + "line": 32 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.inviteFriends", "start": { "column": 17, - "line": 25 + "line": 29 } }, { "defaultMessage": "!!!Logout", "end": { "column": 3, - "line": 32 + "line": 36 }, "file": "src/components/settings/navigation/SettingsNavigation.js", "id": "settings.navigation.logout", "start": { "column": 10, - "line": 29 + "line": 33 } } ], @@ -2202,6 +2215,89 @@ ], "path": "src/components/settings/settings/EditSettingsForm.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!Team", + "end": { + "column": 3, + "line": 16 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.headline", + "start": { + "column": 12, + "line": 13 + } + }, + { + "defaultMessage": "!!!Franz for Teams", + "end": { + "column": 3, + "line": 20 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.contentHeadline", + "start": { + "column": 19, + "line": 17 + } + }, + { + "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "end": { + "column": 3, + "line": 24 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.intro", + "start": { + "column": 9, + "line": 21 + } + }, + { + "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "end": { + "column": 3, + "line": 28 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.copy", + "start": { + "column": 8, + "line": 25 + } + }, + { + "defaultMessage": "!!!Manage your Team", + "end": { + "column": 3, + "line": 32 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.manageAction", + "start": { + "column": 16, + "line": 29 + } + }, + { + "defaultMessage": "!!!Upgrade your Account", + "end": { + "column": 3, + "line": 36 + }, + "file": "src/components/settings/team/TeamDashboard.js", + "id": "settings.team.upgradeAction", + "start": { + "column": 17, + "line": 33 + } + } + ], + "path": "src/components/settings/team/TeamDashboard.json" + }, { "descriptors": [ { @@ -3147,7 +3243,7 @@ } }, { - "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @MeetFranz", + "defaultMessage": "!!! I've added {count} services to Franz! Get the free app for WhatsApp, Messenger, Slack, Skype and co at www.meetfranz.com /cc @FranzMessenger", "end": { "column": 3, "line": 42 diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 06cda4aca..8d46f7e29 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -168,6 +168,7 @@ "settings.navigation.inviteFriends": "Invite Friends", "settings.navigation.logout": "Logout", "settings.navigation.settings": "Settings", + "settings.navigation.team": "Manage Team", "settings.navigation.yourServices": "Your services", "settings.recipes.all": "All services", "settings.recipes.dev": "Development", @@ -226,6 +227,12 @@ "settings.services.tooltip.isMuted": "All sounds are muted", "settings.services.tooltip.notificationsDisabled": "Notifications are disabled", "settings.services.updatedInfo": "Your changes have been saved", + "settings.team.contentHeadline": "Franz for Teams", + "settings.team.copy": "Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "settings.team.headline": "Team", + "settings.team.intro": "You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "settings.team.manageAction": "Manage your Team", + "settings.team.upgradeAction": "Upgrade your Account", "settings.user.form.accountType.company": "Company", "settings.user.form.accountType.individual": "Individual", "settings.user.form.accountType.label": "Account type", diff --git a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json index 785ce9f29..5b854641a 100644 --- a/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json +++ b/src/i18n/messages/src/components/settings/navigation/SettingsNavigation.json @@ -38,16 +38,29 @@ "column": 3 } }, + { + "id": "settings.navigation.team", + "defaultMessage": "!!!Manage Team", + "file": "src/components/settings/navigation/SettingsNavigation.js", + "start": { + "line": 21, + "column": 8 + }, + "end": { + "line": 24, + "column": 3 + } + }, { "id": "settings.navigation.settings", "defaultMessage": "!!!Settings", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 21, + "line": 25, "column": 12 }, "end": { - "line": 24, + "line": 28, "column": 3 } }, @@ -56,11 +69,11 @@ "defaultMessage": "!!!Invite Friends", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 25, + "line": 29, "column": 17 }, "end": { - "line": 28, + "line": 32, "column": 3 } }, @@ -69,11 +82,11 @@ "defaultMessage": "!!!Logout", "file": "src/components/settings/navigation/SettingsNavigation.js", "start": { - "line": 29, + "line": 33, "column": 10 }, "end": { - "line": 32, + "line": 36, "column": 3 } } diff --git a/src/i18n/messages/src/components/settings/team/TeamDashboard.json b/src/i18n/messages/src/components/settings/team/TeamDashboard.json new file mode 100644 index 000000000..91b6754ea --- /dev/null +++ b/src/i18n/messages/src/components/settings/team/TeamDashboard.json @@ -0,0 +1,80 @@ +[ + { + "id": "settings.team.headline", + "defaultMessage": "!!!Team", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 14, + "column": 12 + }, + "end": { + "line": 17, + "column": 3 + } + }, + { + "id": "settings.team.contentHeadline", + "defaultMessage": "!!!Franz for Teams", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 18, + "column": 19 + }, + "end": { + "line": 21, + "column": 3 + } + }, + { + "id": "settings.team.intro", + "defaultMessage": "!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 22, + "column": 9 + }, + "end": { + "line": 25, + "column": 3 + } + }, + { + "id": "settings.team.copy", + "defaultMessage": "!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 26, + "column": 8 + }, + "end": { + "line": 29, + "column": 3 + } + }, + { + "id": "settings.team.manageAction", + "defaultMessage": "!!!Manage your Team", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 30, + "column": 16 + }, + "end": { + "line": 33, + "column": 3 + } + }, + { + "id": "settings.team.upgradeAction", + "defaultMessage": "!!!Upgrade your Account", + "file": "src/components/settings/team/TeamDashboard.js", + "start": { + "line": 34, + "column": 17 + }, + "end": { + "line": 37, + "column": 3 + } + } +] \ No newline at end of file -- cgit v1.2.3-70-g09d2 From b92541305cbeaf32f54ed2751f4ddd880baa2b69 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 16:01:39 +0200 Subject: Clean up --- src/components/settings/team/TeamDashboard.js | 6 ++---- src/containers/settings/TeamScreen.js | 5 ----- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js index a29a262e9..e222bb14c 100644 --- a/src/components/settings/team/TeamDashboard.js +++ b/src/components/settings/team/TeamDashboard.js @@ -37,11 +37,11 @@ const messages = defineMessages({ }, }); -const styles = theme => ({ +const styles = { cta: { marginTop: 40, }, -}); +}; export default @injectSheet(styles) @observer class TeamDashboard extends Component { @@ -51,7 +51,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon userInfoRequestFailed: PropTypes.bool.isRequired, retryUserInfoRequest: PropTypes.func.isRequired, openTeamManagement: PropTypes.func.isRequired, - upgradeAccount: PropTypes.func.isRequired, classes: PropTypes.object.isRequired, }; @@ -66,7 +65,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon userInfoRequestFailed, retryUserInfoRequest, openTeamManagement, - upgradeAccount, classes, } = this.props; const { intl } = this.context; diff --git a/src/containers/settings/TeamScreen.js b/src/containers/settings/TeamScreen.js index 3a4b7ef77..30b0895e3 100644 --- a/src/containers/settings/TeamScreen.js +++ b/src/containers/settings/TeamScreen.js @@ -1,9 +1,7 @@ -import { remote } from 'electron'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; import { inject, observer } from 'mobx-react'; -import PaymentStore from '../../stores/PaymentStore'; import UserStore from '../../stores/UserStore'; import AppStore from '../../stores/AppStore'; @@ -11,8 +9,6 @@ import TeamDashboard from '../../components/settings/team/TeamDashboard'; import ErrorBoundary from '../../components/util/ErrorBoundary'; import { WEBSITE } from '../../environment'; -const { BrowserWindow } = remote; - export default @inject('stores', 'actions') @observer class TeamScreen extends Component { handleWebsiteLink(route) { const { actions, stores } = this.props; @@ -45,7 +41,6 @@ export default @inject('stores', 'actions') @observer class TeamScreen extends C TeamScreen.wrappedComponent.propTypes = { stores: PropTypes.shape({ user: PropTypes.instanceOf(UserStore).isRequired, - payment: PropTypes.instanceOf(PaymentStore).isRequired, app: PropTypes.instanceOf(AppStore).isRequired, }).isRequired, actions: PropTypes.shape({ -- cgit v1.2.3-70-g09d2 From 827e4b7727e7f4abcb5472eb84c45c3f65efaf9c Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Mon, 8 Apr 2019 16:40:44 +0200 Subject: Restore classic layout when user has no subscription --- .../settings/account/AccountDashboard.js | 47 ++++++++++++---------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js index ca8b9e1bd..2a9c9a599 100644 --- a/src/components/settings/account/AccountDashboard.js +++ b/src/components/settings/account/AccountDashboard.js @@ -164,28 +164,33 @@ export default @observer class AccountDashboard extends Component { {user.organization && `${user.organization}, `} {user.email} -
-
+ {user.isSubscriptionOwner && ( +
+
+ )} + {!user.isSubscriptionOwner && ( +