aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/settings
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/settings')
-rw-r--r--src/components/settings/account/AccountDashboard.js147
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js16
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js58
-rw-r--r--src/components/settings/services/EditServiceForm.js124
-rw-r--r--src/components/settings/services/ServicesDashboard.js2
-rw-r--r--src/components/settings/settings/EditSettingsForm.js29
-rw-r--r--src/components/settings/team/TeamDashboard.js39
7 files changed, 100 insertions, 315 deletions
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 68d88e218..d3d75a979 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -3,14 +3,11 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import ReactTooltip from 'react-tooltip'; 5import ReactTooltip from 'react-tooltip';
6import { ProBadge, H1, H2 } from '@meetfranz/ui'; 6import { H1, H2 } from '@meetfranz/ui';
7import moment from 'moment';
8 7
9import Loader from '../../ui/Loader'; 8import Loader from '../../ui/Loader';
10import Button from '../../ui/Button'; 9import Button from '../../ui/Button';
11import Infobox from '../../ui/Infobox'; 10import Infobox from '../../ui/Infobox';
12import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen';
13import { i18nPlanName } from '../../../helpers/plan-helpers';
14import { LOCAL_SERVER, LIVE_FRANZ_API } from '../../../config'; 11import { LOCAL_SERVER, LIVE_FRANZ_API } from '../../../config';
15 12
16const messages = defineMessages({ 13const messages = defineMessages({
@@ -30,18 +27,6 @@ const messages = defineMessages({
30 id: 'settings.account.manageSubscription.label', 27 id: 'settings.account.manageSubscription.label',
31 defaultMessage: '!!!Manage your subscription', 28 defaultMessage: '!!!Manage your subscription',
32 }, 29 },
33 upgradeAccountToPro: {
34 id: 'settings.account.upgradeToPro.label',
35 defaultMessage: '!!!Upgrade to Franz Professional',
36 },
37 accountTypeBasic: {
38 id: 'settings.account.accountType.basic',
39 defaultMessage: '!!!Basic Account',
40 },
41 accountTypePremium: {
42 id: 'settings.account.accountType.premium',
43 defaultMessage: '!!!Premium Supporter Account',
44 },
45 accountEditButton: { 30 accountEditButton: {
46 id: 'settings.account.account.editButton', 31 id: 'settings.account.account.editButton',
47 defaultMessage: '!!!Edit Account', 32 defaultMessage: '!!!Edit Account',
@@ -76,23 +61,10 @@ const messages = defineMessages({
76 defaultMessage: 61 defaultMessage:
77 '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!', 62 '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!',
78 }, 63 },
79 trial: {
80 id: 'settings.account.trial',
81 defaultMessage: '!!!Free Trial',
82 },
83 yourLicense: { 64 yourLicense: {
84 id: 'settings.account.yourLicense', 65 id: 'settings.account.yourLicense',
85 defaultMessage: '!!!Your Franz License:', 66 defaultMessage: '!!!Your Franz License:',
86 }, 67 },
87 trialEndsIn: {
88 id: 'settings.account.trialEndsIn',
89 defaultMessage: '!!!Your free trial ends in {duration}.',
90 },
91 trialUpdateBillingInformation: {
92 id: 'settings.account.trialUpdateBillingInfo',
93 defaultMessage:
94 '!!!Please update your billing info to continue using {license} after your trial period.',
95 },
96 accountUnavailable: { 68 accountUnavailable: {
97 id: 'settings.account.accountUnavailable', 69 id: 'settings.account.accountUnavailable',
98 defaultMessage: 'Account is unavailable', 70 defaultMessage: 'Account is unavailable',
@@ -107,8 +79,6 @@ const messages = defineMessages({
107class AccountDashboard extends Component { 79class AccountDashboard extends Component {
108 static propTypes = { 80 static propTypes = {
109 user: MobxPropTypes.observableObject.isRequired, 81 user: MobxPropTypes.observableObject.isRequired,
110 isPremiumOverrideUser: PropTypes.bool.isRequired,
111 isProUser: PropTypes.bool.isRequired,
112 isLoading: PropTypes.bool.isRequired, 82 isLoading: PropTypes.bool.isRequired,
113 userInfoRequestFailed: PropTypes.bool.isRequired, 83 userInfoRequestFailed: PropTypes.bool.isRequired,
114 retryUserInfoRequest: PropTypes.func.isRequired, 84 retryUserInfoRequest: PropTypes.func.isRequired,
@@ -116,10 +86,7 @@ class AccountDashboard extends Component {
116 isLoadingDeleteAccount: PropTypes.bool.isRequired, 86 isLoadingDeleteAccount: PropTypes.bool.isRequired,
117 isDeleteAccountSuccessful: PropTypes.bool.isRequired, 87 isDeleteAccountSuccessful: PropTypes.bool.isRequired,
118 openEditAccount: PropTypes.func.isRequired, 88 openEditAccount: PropTypes.func.isRequired,
119 openBilling: PropTypes.func.isRequired,
120 upgradeToPro: PropTypes.func.isRequired,
121 openInvoices: PropTypes.func.isRequired, 89 openInvoices: PropTypes.func.isRequired,
122 onCloseSubscriptionWindow: PropTypes.func.isRequired,
123 server: PropTypes.string.isRequired, 90 server: PropTypes.string.isRequired,
124 }; 91 };
125 92
@@ -130,8 +97,6 @@ class AccountDashboard extends Component {
130 render() { 97 render() {
131 const { 98 const {
132 user, 99 user,
133 isPremiumOverrideUser,
134 isProUser,
135 isLoading, 100 isLoading,
136 userInfoRequestFailed, 101 userInfoRequestFailed,
137 retryUserInfoRequest, 102 retryUserInfoRequest,
@@ -139,20 +104,11 @@ class AccountDashboard extends Component {
139 isLoadingDeleteAccount, 104 isLoadingDeleteAccount,
140 isDeleteAccountSuccessful, 105 isDeleteAccountSuccessful,
141 openEditAccount, 106 openEditAccount,
142 openBilling,
143 upgradeToPro,
144 openInvoices, 107 openInvoices,
145 onCloseSubscriptionWindow,
146 server, 108 server,
147 } = this.props; 109 } = this.props;
148 const { intl } = this.context; 110 const { intl } = this.context;
149 111
150 let planName = '';
151
152 if (user.team && user.team.plan) {
153 planName = i18nPlanName(user.team.plan, intl);
154 }
155
156 const isUsingWithoutAccount = server === LOCAL_SERVER; 112 const isUsingWithoutAccount = server === LOCAL_SERVER;
157 const isUsingFranzServer = server === LIVE_FRANZ_API; 113 const isUsingFranzServer = server === LIVE_FRANZ_API;
158 114
@@ -210,98 +166,40 @@ class AccountDashboard extends Component {
210 <div className="account__info"> 166 <div className="account__info">
211 <H1> 167 <H1>
212 <span className="username">{`${user.firstname} ${user.lastname}`}</span> 168 <span className="username">{`${user.firstname} ${user.lastname}`}</span>
213 {user.isPremium && (
214 <>
215 {' '}
216 <ProBadge />
217 </>
218 )}
219 </H1> 169 </H1>
220 <p> 170 <p>
221 {user.organization && `${user.organization}, `} 171 {user.organization && `${user.organization}, `}
222 {user.email} 172 {user.email}
223 </p> 173 </p>
224 {user.isPremium && ( 174 <div className="manage-user-links">
225 <div className="manage-user-links"> 175 <Button
226 <Button 176 label={intl.formatMessage(
227 label={intl.formatMessage( 177 messages.accountEditButton,
228 messages.accountEditButton, 178 )}
229 )} 179 className="franz-form__button--inverted"
230 className="franz-form__button--inverted" 180 onClick={openEditAccount}
231 onClick={openEditAccount} 181 />
232 /> 182 </div>
233 </div>
234 )}
235 </div> 183 </div>
236 {!user.isPremium && ( 184 <Button
237 <Button 185 label={intl.formatMessage(
238 label={intl.formatMessage( 186 messages.accountEditButton,
239 messages.accountEditButton, 187 )}
240 )} 188 className="franz-form__button--inverted"
241 className="franz-form__button--inverted" 189 onClick={openEditAccount}
242 onClick={openEditAccount} 190 />
243 />
244 )}
245 </div> 191 </div>
246 </div> 192 </div>
247 {user.isPremium && user.isSubscriptionOwner && isUsingFranzServer && ( 193 {user.isSubscriptionOwner && isUsingFranzServer && (
248 <div className="account"> 194 <div className="account">
249 <div className="account__box"> 195 <div className="account__box">
250 <H2>{intl.formatMessage(messages.yourLicense)}</H2> 196 <H2>{intl.formatMessage(messages.yourLicense)}</H2>
251 <p> 197 <p>
252 Franz 198 Franz
253 {' '}
254 {isPremiumOverrideUser ? 'Premium' : planName}
255 {user.team.isTrial && (
256 <>
257 {' – '}
258 {intl.formatMessage(messages.trial)}
259 </>
260 )}
261 </p> 199 </p>
262 {user.team.isTrial && (
263 <>
264 <br />
265 <p>
266 {intl.formatMessage(messages.trialEndsIn, {
267 duration: moment
268 .duration(
269 moment().diff(user.team.trialEnd),
270 )
271 .humanize(),
272 })}
273 </p>
274 <p>
275 {intl.formatMessage(
276 messages.trialUpdateBillingInformation,
277 {
278 license: planName,
279 },
280 )}
281 </p>
282 </>
283 )}
284 {!isProUser && (
285 <div className="manage-user-links">
286 <Button
287 label={intl.formatMessage(
288 messages.upgradeAccountToPro,
289 )}
290 className="franz-form__button--primary"
291 onClick={upgradeToPro}
292 />
293 </div>
294 )}
295 <div className="manage-user-links"> 200 <div className="manage-user-links">
296 <Button 201 <Button
297 label={intl.formatMessage( 202 label={intl.formatMessage(
298 messages.manageSubscriptionButtonLabel,
299 )}
300 className="franz-form__button--inverted"
301 onClick={openBilling}
302 />
303 <Button
304 label={intl.formatMessage(
305 messages.invoicesButton, 203 messages.invoicesButton,
306 )} 204 )}
307 className="franz-form__button--inverted" 205 className="franz-form__button--inverted"
@@ -311,15 +209,6 @@ class AccountDashboard extends Component {
311 </div> 209 </div>
312 </div> 210 </div>
313 )} 211 )}
314 {!user.isPremium && (
315 <div className="account franz-form">
316 <div className="account__box">
317 <SubscriptionForm
318 onCloseWindow={onCloseSubscriptionWindow}
319 />
320 </div>
321 </div>
322 )}
323 </> 212 </>
324 )} 213 )}
325 214
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index cebab2f12..02cae6b69 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -2,7 +2,6 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { defineMessages, intlShape } from 'react-intl'; 3import { defineMessages, intlShape } from 'react-intl';
4import { inject, observer } from 'mobx-react'; 4import { inject, observer } from 'mobx-react';
5import { ProBadge } from '@meetfranz/ui';
6import { RouterStore } from 'mobx-react-router'; 5import { RouterStore } from 'mobx-react-router';
7 6
8import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config'; 7import { LOCAL_SERVER, LIVE_FERDI_API, LIVE_FRANZ_API } from '../../../config';
@@ -11,7 +10,6 @@ import { workspaceStore } from '../../../features/workspaces';
11import UIStore from '../../../stores/UIStore'; 10import UIStore from '../../../stores/UIStore';
12import SettingsStore from '../../../stores/SettingsStore'; 11import SettingsStore from '../../../stores/SettingsStore';
13import UserStore from '../../../stores/UserStore'; 12import UserStore from '../../../stores/UserStore';
14import { serviceLimitStore } from '../../../features/serviceLimit';
15 13
16const messages = defineMessages({ 14const messages = defineMessages({
17 availableServices: { 15 availableServices: {
@@ -98,8 +96,6 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
98 96
99 render() { 97 render() {
100 const { serviceCount, workspaceCount, stores } = this.props; 98 const { serviceCount, workspaceCount, stores } = this.props;
101 const { isDarkThemeActive } = stores.ui;
102 const { router, user } = stores;
103 const { intl } = this.context; 99 const { intl } = this.context;
104 const isLoggedIn = Boolean(localStorage.getItem('authToken')); 100 const isLoggedIn = Boolean(localStorage.getItem('authToken'));
105 const isUsingWithoutAccount = stores.settings.app.server === LOCAL_SERVER; 101 const isUsingWithoutAccount = stores.settings.app.server === LOCAL_SERVER;
@@ -124,9 +120,6 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
124 {' '} 120 {' '}
125 <span className="badge"> 121 <span className="badge">
126 {serviceCount} 122 {serviceCount}
127 {serviceLimitStore.serviceLimit !== 0 && (
128 `/${serviceLimitStore.serviceLimit}`
129 )}
130 </span> 123 </span>
131 </Link> 124 </Link>
132 {workspaceStore.isFeatureEnabled ? ( 125 {workspaceStore.isFeatureEnabled ? (
@@ -138,11 +131,7 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
138 > 131 >
139 {intl.formatMessage(messages.yourWorkspaces)} 132 {intl.formatMessage(messages.yourWorkspaces)}
140 {' '} 133 {' '}
141 {workspaceStore.isPremiumUpgradeRequired ? ( 134 <span className="badge">{workspaceCount}</span>
142 <ProBadge inverted={!isDarkThemeActive && workspaceStore.isSettingsRouteActive} />
143 ) : (
144 <span className="badge">{workspaceCount}</span>
145 )}
146 </Link> 135 </Link>
147 ) : null} 136 ) : null}
148 {!isUsingWithoutAccount && ( 137 {!isUsingWithoutAccount && (
@@ -163,9 +152,6 @@ export default @inject('stores', 'actions') @observer class SettingsNavigation e
163 disabled={!isLoggedIn} 152 disabled={!isLoggedIn}
164 > 153 >
165 {intl.formatMessage(messages.team)} 154 {intl.formatMessage(messages.team)}
166 {!user.data.isPremium && (
167 <ProBadge inverted={!isDarkThemeActive && router.location.pathname === '/settings/team'} />
168 )}
169 </Link> 155 </Link>
170 )} 156 )}
171 <Link 157 <Link
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index b4e2fc05c..e82324cff 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -13,8 +13,6 @@ import RecipeItem from './RecipeItem';
13import Loader from '../../ui/Loader'; 13import Loader from '../../ui/Loader';
14import Appear from '../../ui/effects/Appear'; 14import Appear from '../../ui/effects/Appear';
15import { FRANZ_SERVICE_REQUEST } from '../../../config'; 15import { FRANZ_SERVICE_REQUEST } from '../../../config';
16import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
17import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
18import RecipePreview from '../../../models/RecipePreview'; 16import RecipePreview from '../../../models/RecipePreview';
19 17
20const messages = defineMessages({ 18const messages = defineMessages({
@@ -120,7 +118,6 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
120 openRecipeDirectory: PropTypes.func.isRequired, 118 openRecipeDirectory: PropTypes.func.isRequired,
121 openDevDocs: PropTypes.func.isRequired, 119 openDevDocs: PropTypes.func.isRequired,
122 classes: PropTypes.object.isRequired, 120 classes: PropTypes.object.isRequired,
123 isCommunityRecipesIncludedInCurrentPlan: PropTypes.bool.isRequired,
124 }; 121 };
125 122
126 static defaultProps = { 123 static defaultProps = {
@@ -148,7 +145,6 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
148 openRecipeDirectory, 145 openRecipeDirectory,
149 openDevDocs, 146 openDevDocs,
150 classes, 147 classes,
151 isCommunityRecipesIncludedInCurrentPlan,
152 } = this.props; 148 } = this.props;
153 const { intl } = this.context; 149 const { intl } = this.context;
154 150
@@ -163,7 +159,6 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
163 <div className="settings__header"> 159 <div className="settings__header">
164 <h1>{intl.formatMessage(messages.headline)}</h1> 160 <h1>{intl.formatMessage(messages.headline)}</h1>
165 </div> 161 </div>
166 <LimitReachedInfobox />
167 <div className="settings__body recipes"> 162 <div className="settings__body recipes">
168 {serviceStatus.length > 0 && serviceStatus.includes('created') && ( 163 {serviceStatus.length > 0 && serviceStatus.includes('created') && (
169 <Appear> 164 <Appear>
@@ -223,9 +218,6 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
223 <> 218 <>
224 <H2> 219 <H2>
225 {intl.formatMessage(messages.headlineCustomRecipes)} 220 {intl.formatMessage(messages.headlineCustomRecipes)}
226 {!isCommunityRecipesIncludedInCurrentPlan && (
227 <ProBadge className={classes.proBadge} />
228 )}
229 </H2> 221 </H2>
230 <div className={classes.devRecipeIntroContainer}> 222 <div className={classes.devRecipeIntroContainer}>
231 <p> 223 <p>
@@ -251,37 +243,33 @@ export default @injectSheet(styles) @observer class RecipesDashboard extends Com
251 </div> 243 </div>
252 </> 244 </>
253 )} 245 )}
254 <PremiumFeatureContainer 246 {recipeFilter === 'dev' && communityRecipes.length > 0 && (
255 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && !isCommunityRecipesIncludedInCurrentPlan} 247 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3>
256 > 248 )}
257 {recipeFilter === 'dev' && communityRecipes.length > 0 && ( 249 <div className="recipes__list">
258 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3> 250 {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && (
259 )} 251 <div className="align-middle settings__empty-state">
260 <div className="recipes__list"> 252 <span className="emoji">
261 {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && ( 253 <img src="./assets/images/emoji/dontknow.png" alt="" />
262 <div className="align-middle settings__empty-state"> 254 </span>
263 <span className="emoji">
264 <img src="./assets/images/emoji/dontknow.png" alt="" />
265 </span>
266 255
267 <p className="settings__empty-state-text">{intl.formatMessage(messages.nothingFound)}</p> 256 <p className="settings__empty-state-text">{intl.formatMessage(messages.nothingFound)}</p>
268 257
269 <RecipeItem
270 key={customWebsiteRecipe.id}
271 recipe={customWebsiteRecipe}
272 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: customWebsiteRecipe.id })}
273 />
274 </div>
275 )}
276 {communityRecipes.map(recipe => (
277 <RecipeItem 258 <RecipeItem
278 key={recipe.id} 259 key={customWebsiteRecipe.id}
279 recipe={recipe} 260 recipe={customWebsiteRecipe}
280 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: recipe.id })} 261 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: customWebsiteRecipe.id })}
281 /> 262 />
282 ))} 263 </div>
283 </div> 264 )}
284 </PremiumFeatureContainer> 265 {communityRecipes.map(recipe => (
266 <RecipeItem
267 key={recipe.id}
268 recipe={recipe}
269 onClick={() => isLoggedIn && showAddServiceInterface({ recipeId: recipe.id })}
270 />
271 ))}
272 </div>
285 {recipeFilter === 'dev' && devRecipes.length > 0 && ( 273 {recipeFilter === 'dev' && devRecipes.length > 0 && (
286 <div className={classes.devRecipeList}> 274 <div className={classes.devRecipeList}>
287 <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3> 275 <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3>
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index 513c75eed..0f7c29de5 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -6,7 +6,6 @@ import { defineMessages, intlShape } from 'react-intl';
6import normalizeUrl from 'normalize-url'; 6import normalizeUrl from 'normalize-url';
7 7
8import Form from '../../../lib/Form'; 8import Form from '../../../lib/Form';
9import User from '../../../models/User';
10import Recipe from '../../../models/Recipe'; 9import Recipe from '../../../models/Recipe';
11import Service from '../../../models/Service'; 10import Service from '../../../models/Service';
12import Tabs, { TabItem } from '../../ui/Tabs'; 11import Tabs, { TabItem } from '../../ui/Tabs';
@@ -17,9 +16,6 @@ import Button from '../../ui/Button';
17import ImageUpload from '../../ui/ImageUpload'; 16import ImageUpload from '../../ui/ImageUpload';
18import Select from '../../ui/Select'; 17import Select from '../../ui/Select';
19 18
20import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
21import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
22import { serviceLimitStore } from '../../../features/serviceLimit';
23import { isMac } from '../../../environment'; 19import { isMac } from '../../../environment';
24import globalMessages from '../../../i18n/globalMessages'; 20import globalMessages from '../../../i18n/globalMessages';
25 21
@@ -80,14 +76,6 @@ const messages = defineMessages({
80 id: 'settings.service.form.customUrlValidationError', 76 id: 'settings.service.form.customUrlValidationError',
81 defaultMessage: '!!!Could not validate custom {name} server.', 77 defaultMessage: '!!!Could not validate custom {name} server.',
82 }, 78 },
83 customUrlPremiumInfo: {
84 id: 'settings.service.form.customUrlPremiumInfo',
85 defaultMessage: '!!!To add self hosted services, you need a Ferdi Premium Supporter Account.',
86 },
87 customUrlUpgradeAccount: {
88 id: 'settings.service.form.customUrlUpgradeAccount',
89 defaultMessage: '!!!Upgrade your account',
90 },
91 indirectMessageInfo: { 79 indirectMessageInfo: {
92 id: 'settings.service.form.indirectMessageInfo', 80 id: 'settings.service.form.indirectMessageInfo',
93 defaultMessage: '!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...', 81 defaultMessage: '!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...',
@@ -149,7 +137,6 @@ export default @observer class EditServiceForm extends Component {
149 137
150 return null; 138 return null;
151 }, 139 },
152 user: PropTypes.instanceOf(User).isRequired,
153 action: PropTypes.string.isRequired, 140 action: PropTypes.string.isRequired,
154 form: PropTypes.instanceOf(Form).isRequired, 141 form: PropTypes.instanceOf(Form).isRequired,
155 onSubmit: PropTypes.func.isRequired, 142 onSubmit: PropTypes.func.isRequired,
@@ -158,8 +145,6 @@ export default @observer class EditServiceForm extends Component {
158 isSaving: PropTypes.bool.isRequired, 145 isSaving: PropTypes.bool.isRequired,
159 isDeleting: PropTypes.bool.isRequired, 146 isDeleting: PropTypes.bool.isRequired,
160 isProxyFeatureEnabled: PropTypes.bool.isRequired, 147 isProxyFeatureEnabled: PropTypes.bool.isRequired,
161 isServiceProxyIncludedInCurrentPlan: PropTypes.bool.isRequired,
162 isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired,
163 isHibernationFeatureActive: PropTypes.bool.isRequired, 148 isHibernationFeatureActive: PropTypes.bool.isRequired,
164 }; 149 };
165 150
@@ -217,15 +202,12 @@ export default @observer class EditServiceForm extends Component {
217 recipe, 202 recipe,
218 service, 203 service,
219 action, 204 action,
220 user,
221 form, 205 form,
222 isSaving, 206 isSaving,
223 isDeleting, 207 isDeleting,
224 onDelete, 208 onDelete,
225 openRecipeFile, 209 openRecipeFile,
226 isProxyFeatureEnabled, 210 isProxyFeatureEnabled,
227 isServiceProxyIncludedInCurrentPlan,
228 isSpellcheckerIncludedInCurrentPlan,
229 isHibernationFeatureActive, 211 isHibernationFeatureActive,
230 } = this.props; 212 } = this.props;
231 const { intl } = this.context; 213 const { intl } = this.context;
@@ -285,7 +267,6 @@ export default @observer class EditServiceForm extends Component {
285 )} 267 )}
286 </span> 268 </span>
287 </div> 269 </div>
288 <LimitReachedInfobox />
289 <div className="settings__body"> 270 <div className="settings__body">
290 <form onSubmit={e => this.submit(e)} id="form"> 271 <form onSubmit={e => this.submit(e)} id="form">
291 <div className="service-name"> 272 <div className="service-name">
@@ -311,24 +292,11 @@ export default @observer class EditServiceForm extends Component {
311 )} 292 )}
312 {recipe.hasCustomUrl && ( 293 {recipe.hasCustomUrl && (
313 <TabItem title={intl.formatMessage(messages.tabOnPremise)}> 294 <TabItem title={intl.formatMessage(messages.tabOnPremise)}>
314 {user.isPremium || recipe.author.find(a => a.email === user.email) ? ( 295 <Input field={form.$('customUrl')} />
315 <> 296 {form.error === 'url-validation-error' && (
316 <Input field={form.$('customUrl')} /> 297 <p className="franz-form__error">
317 {form.error === 'url-validation-error' && ( 298 {intl.formatMessage(messages.customUrlValidationError, { name: recipe.name })}
318 <p className="franz-form__error"> 299 </p>
319 {intl.formatMessage(messages.customUrlValidationError, { name: recipe.name })}
320 </p>
321 )}
322 </>
323 ) : (
324 <div className="center premium-info">
325 <p>{intl.formatMessage(messages.customUrlPremiumInfo)}</p>
326 <p>
327 <Link to="/settings/user" className="button">
328 {intl.formatMessage(messages.customUrlUpgradeAccount)}
329 </Link>
330 </p>
331 </div>
332 )} 300 )}
333 </TabItem> 301 </TabItem>
334 )} 302 )}
@@ -403,56 +371,46 @@ export default @observer class EditServiceForm extends Component {
403 </div> 371 </div>
404 372
405 {!isMac && ( 373 {!isMac && (
406 <PremiumFeatureContainer 374 <div className="settings__settings-group">
407 condition={!isSpellcheckerIncludedInCurrentPlan} 375 <Select field={form.$('spellcheckerLanguage')} />
408 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} 376 </div>
409 >
410 <div className="settings__settings-group">
411 <Select field={form.$('spellcheckerLanguage')} />
412 </div>
413 </PremiumFeatureContainer>
414 )} 377 )}
415 378
416 {isProxyFeatureEnabled && ( 379 {isProxyFeatureEnabled && (
417 <PremiumFeatureContainer 380 <div className="settings__settings-group">
418 condition={!isServiceProxyIncludedInCurrentPlan} 381 <h3>
419 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'proxy' }} 382 {intl.formatMessage(messages.headlineProxy)}
420 > 383 <span className="badge badge--success">beta</span>
421 <div className="settings__settings-group"> 384 </h3>
422 <h3> 385 <Toggle field={form.$('proxy.isEnabled')} />
423 {intl.formatMessage(messages.headlineProxy)} 386 {form.$('proxy.isEnabled').value && (
424 <span className="badge badge--success">beta</span> 387 <>
425 </h3> 388 <div className="grid">
426 <Toggle field={form.$('proxy.isEnabled')} /> 389 <div className="grid__row">
427 {form.$('proxy.isEnabled').value && ( 390 <Input field={form.$('proxy.host')} className="proxyHost" />
428 <> 391 <Input field={form.$('proxy.port')} />
429 <div className="grid">
430 <div className="grid__row">
431 <Input field={form.$('proxy.host')} className="proxyHost" />
432 <Input field={form.$('proxy.port')} />
433 </div>
434 </div> 392 </div>
435 <div className="grid"> 393 </div>
436 <div className="grid__row"> 394 <div className="grid">
437 <Input field={form.$('proxy.user')} /> 395 <div className="grid__row">
438 <Input 396 <Input field={form.$('proxy.user')} />
439 field={form.$('proxy.password')} 397 <Input
440 showPasswordToggle 398 field={form.$('proxy.password')}
441 /> 399 showPasswordToggle
442 </div> 400 />
443 </div> 401 </div>
444 <p> 402 </div>
445 <span className="mdi mdi-information" /> 403 <p>
446 {intl.formatMessage(messages.proxyRestartInfo)} 404 <span className="mdi mdi-information" />
447 </p> 405 {intl.formatMessage(messages.proxyRestartInfo)}
448 <p> 406 </p>
449 <span className="mdi mdi-information" /> 407 <p>
450 {intl.formatMessage(messages.proxyInfo)} 408 <span className="mdi mdi-information" />
451 </p> 409 {intl.formatMessage(messages.proxyInfo)}
452 </> 410 </p>
453 )} 411 </>
454 </div> 412 )}
455 </PremiumFeatureContainer> 413 </div>
456 )} 414 )}
457 415
458 <div className="user-agent"> 416 <div className="user-agent">
@@ -512,7 +470,7 @@ export default @observer class EditServiceForm extends Component {
512 type="submit" 470 type="submit"
513 label={intl.formatMessage(messages.saveService)} 471 label={intl.formatMessage(messages.saveService)}
514 htmlForm="form" 472 htmlForm="form"
515 disabled={action !== 'edit' && ((form.isPristine && requiresUserInput) || serviceLimitStore.userHasReachedServiceLimit)} 473 disabled={action !== 'edit' && (form.isPristine && requiresUserInput)}
516 /> 474 />
517 )} 475 )}
518 </div> 476 </div>
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js
index a0f05fd20..a05af5da0 100644
--- a/src/components/settings/services/ServicesDashboard.js
+++ b/src/components/settings/services/ServicesDashboard.js
@@ -10,7 +10,6 @@ import Loader from '../../ui/Loader';
10import FAB from '../../ui/FAB'; 10import FAB from '../../ui/FAB';
11import ServiceItem from './ServiceItem'; 11import ServiceItem from './ServiceItem';
12import Appear from '../../ui/effects/Appear'; 12import Appear from '../../ui/effects/Appear';
13import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
14 13
15const messages = defineMessages({ 14const messages = defineMessages({
16 headline: { 15 headline: {
@@ -93,7 +92,6 @@ export default @observer class ServicesDashboard extends Component {
93 <div className="settings__header"> 92 <div className="settings__header">
94 <h1>{intl.formatMessage(messages.headline)}</h1> 93 <h1>{intl.formatMessage(messages.headline)}</h1>
95 </div> 94 </div>
96 <LimitReachedInfobox />
97 <div className="settings__body"> 95 <div className="settings__body">
98 {(services.length !== 0 || searchNeedle) && !isLoading && ( 96 {(services.length !== 0 || searchNeedle) && !isLoading && (
99 <SearchInput 97 <SearchInput
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 52b26d65b..a8ba8748d 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -10,7 +10,6 @@ import Button from '../../ui/Button';
10import Toggle from '../../ui/Toggle'; 10import Toggle from '../../ui/Toggle';
11import ToggleRaw from '../../ui/ToggleRaw'; 11import ToggleRaw from '../../ui/ToggleRaw';
12import Select from '../../ui/Select'; 12import Select from '../../ui/Select';
13import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
14import Input from '../../ui/Input'; 13import Input from '../../ui/Input';
15 14
16import { 15import {
@@ -168,7 +167,6 @@ export default @observer class EditSettingsForm extends Component {
168 isClearingAllCache: PropTypes.bool.isRequired, 167 isClearingAllCache: PropTypes.bool.isRequired,
169 onClearAllCache: PropTypes.func.isRequired, 168 onClearAllCache: PropTypes.func.isRequired,
170 getCacheSize: PropTypes.func.isRequired, 169 getCacheSize: PropTypes.func.isRequired,
171 isSpellcheckerIncludedInCurrentPlan: PropTypes.bool.isRequired,
172 isTodosEnabled: PropTypes.bool.isRequired, 170 isTodosEnabled: PropTypes.bool.isRequired,
173 isTodosActivated: PropTypes.bool.isRequired, 171 isTodosActivated: PropTypes.bool.isRequired,
174 isWorkspaceEnabled: PropTypes.bool.isRequired, 172 isWorkspaceEnabled: PropTypes.bool.isRequired,
@@ -224,7 +222,6 @@ export default @observer class EditSettingsForm extends Component {
224 isClearingAllCache, 222 isClearingAllCache,
225 onClearAllCache, 223 onClearAllCache,
226 getCacheSize, 224 getCacheSize,
227 isSpellcheckerIncludedInCurrentPlan,
228 isTodosEnabled, 225 isTodosEnabled,
229 isWorkspaceEnabled, 226 isWorkspaceEnabled,
230 automaticUpdates, 227 automaticUpdates,
@@ -564,22 +561,16 @@ export default @observer class EditSettingsForm extends Component {
564 561
565 <Hr /> 562 <Hr />
566 563
567 <PremiumFeatureContainer 564 <Toggle
568 condition={!isSpellcheckerIncludedInCurrentPlan} 565 field={form.$('enableSpellchecking')}
569 gaEventInfo={{ category: 'User', event: 'upgrade', label: 'spellchecker' }} 566 />
570 > 567 {!isMac && form.$('enableSpellchecking').value && (
571 <> 568 <Select field={form.$('spellcheckerLanguage')} />
572 <Toggle 569 )}
573 field={form.$('enableSpellchecking')} 570 {isMac && form.$('enableSpellchecking').value && (
574 /> 571 <p>{intl.formatMessage(messages.spellCheckerLanguageInfo)}</p>
575 {!isMac && form.$('enableSpellchecking').value && ( 572 )}
576 <Select field={form.$('spellcheckerLanguage')} /> 573
577 )}
578 {isMac && form.$('enableSpellchecking').value && (
579 <p>{intl.formatMessage(messages.spellCheckerLanguageInfo)}</p>
580 )}
581 </>
582 </PremiumFeatureContainer>
583 <a 574 <a
584 href={FRANZ_TRANSLATION} 575 href={FRANZ_TRANSLATION}
585 target="_blank" 576 target="_blank"
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js
index 602d6e490..437225058 100644
--- a/src/components/settings/team/TeamDashboard.js
+++ b/src/components/settings/team/TeamDashboard.js
@@ -6,12 +6,9 @@ import ReactTooltip from 'react-tooltip';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
7import classnames from 'classnames'; 7import classnames from 'classnames';
8 8
9import { Badge } from '@meetfranz/ui';
10import Loader from '../../ui/Loader'; 9import Loader from '../../ui/Loader';
11import Button from '../../ui/Button'; 10import Button from '../../ui/Button';
12import Infobox from '../../ui/Infobox'; 11import Infobox from '../../ui/Infobox';
13import globalMessages from '../../../i18n/globalMessages';
14import UpgradeButton from '../../ui/UpgradeButton';
15import { LIVE_FRANZ_API } from '../../../config'; 12import { LIVE_FRANZ_API } from '../../../config';
16 13
17const messages = defineMessages({ 14const messages = defineMessages({
@@ -35,10 +32,6 @@ const messages = defineMessages({
35 id: 'settings.team.manageAction', 32 id: 'settings.team.manageAction',
36 defaultMessage: '!!!Manage your Team on meetfranz.com', 33 defaultMessage: '!!!Manage your Team on meetfranz.com',
37 }, 34 },
38 upgradeButton: {
39 id: 'settings.team.upgradeAction',
40 defaultMessage: '!!!Upgrade your Account',
41 },
42 teamsUnavailable: { 35 teamsUnavailable: {
43 id: 'settings.team.teamsUnavailable', 36 id: 'settings.team.teamsUnavailable',
44 defaultMessage: '!!!Teams are unavailable', 37 defaultMessage: '!!!Teams are unavailable',
@@ -88,10 +81,6 @@ const styles = {
88 headlineWithSpacing: { 81 headlineWithSpacing: {
89 marginBottom: 'inherit', 82 marginBottom: 'inherit',
90 }, 83 },
91 proRequired: {
92 margin: [10, 0, 40],
93 height: 'auto',
94 },
95 buttonContainer: { 84 buttonContainer: {
96 display: 'flex', 85 display: 'flex',
97 height: 'auto', 86 height: 'auto',
@@ -105,7 +94,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
105 retryUserInfoRequest: PropTypes.func.isRequired, 94 retryUserInfoRequest: PropTypes.func.isRequired,
106 openTeamManagement: PropTypes.func.isRequired, 95 openTeamManagement: PropTypes.func.isRequired,
107 classes: PropTypes.object.isRequired, 96 classes: PropTypes.object.isRequired,
108 isProUser: PropTypes.bool.isRequired,
109 server: PropTypes.string.isRequired, 97 server: PropTypes.string.isRequired,
110 }; 98 };
111 99
@@ -119,7 +107,6 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
119 userInfoRequestFailed, 107 userInfoRequestFailed,
120 retryUserInfoRequest, 108 retryUserInfoRequest,
121 openTeamManagement, 109 openTeamManagement,
122 isProUser,
123 classes, 110 classes,
124 server, 111 server,
125 } = this.props; 112 } = this.props;
@@ -157,37 +144,25 @@ export default @injectSheet(styles) @observer class TeamDashboard extends Compon
157 <> 144 <>
158 <h1 className={classnames({ 145 <h1 className={classnames({
159 [classes.headline]: true, 146 [classes.headline]: true,
160 [classes.headlineWithSpacing]: isProUser, 147 [classes.headlineWithSpacing]: true,
161 })} 148 })}
162 > 149 >
163 {intl.formatMessage(messages.contentHeadline)} 150 {intl.formatMessage(messages.contentHeadline)}
164 151
165 </h1> 152 </h1>
166 {!isProUser && (
167 <Badge className={classes.proRequired}>{intl.formatMessage(globalMessages.proRequired)}</Badge>
168 )}
169 <div className={classes.container}> 153 <div className={classes.container}>
170 <div className={classes.content}> 154 <div className={classes.content}>
171 <p>{intl.formatMessage(messages.intro)}</p> 155 <p>{intl.formatMessage(messages.intro)}</p>
172 <p>{intl.formatMessage(messages.copy)}</p> 156 <p>{intl.formatMessage(messages.copy)}</p>
173 </div> 157 </div>
174 <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Franz for Teams" /> 158 <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Ferdi for Teams" />
175 </div> 159 </div>
176 <div className={classes.buttonContainer}> 160 <div className={classes.buttonContainer}>
177 {!isProUser ? ( 161 <Button
178 <UpgradeButton 162 label={intl.formatMessage(messages.manageButton)}
179 className={classes.cta} 163 onClick={openTeamManagement}
180 gaEventInfo={{ category: 'Todos', event: 'upgrade' }} 164 className={classes.cta}
181 requiresPro 165 />
182 short
183 />
184 ) : (
185 <Button
186 label={intl.formatMessage(messages.manageButton)}
187 onClick={openTeamManagement}
188 className={classes.cta}
189 />
190 )}
191 </div> 166 </div>
192 </> 167 </>
193 </> 168 </>