From 1bae1dfcbc4a5f590c51103635006198ae6a91d6 Mon Sep 17 00:00:00 2001 From: Stefan Malzner Date: Tue, 30 Apr 2019 15:23:38 +0200 Subject: Enforce service limit --- packages/ui/src/infobox/index.tsx | 2 +- .../settings/recipes/RecipesDashboard.js | 2 + .../settings/services/EditServiceForm.js | 5 +- .../settings/services/ServicesDashboard.js | 2 + .../serviceLimit/components/LimitReachedInfobox.js | 74 ++++++++ src/features/serviceLimit/index.js | 33 ++++ src/features/serviceLimit/store.js | 41 +++++ src/i18n/locales/defaultMessages.json | 205 +++++++++++++-------- src/i18n/locales/en-US.json | 3 +- .../settings/recipes/RecipesDashboard.json | 32 ++-- .../settings/services/EditServiceForm.json | 88 ++++----- .../settings/services/ServicesDashboard.json | 36 ++-- .../components/AnnouncementScreen.json | 15 ++ .../components/LimitReachedInfobox.json | 28 +++ src/stores/FeaturesStore.js | 2 + src/stores/ServicesStore.js | 3 + src/stores/index.js | 2 + 17 files changed, 414 insertions(+), 159 deletions(-) create mode 100644 src/features/serviceLimit/components/LimitReachedInfobox.js create mode 100644 src/features/serviceLimit/index.js create mode 100644 src/features/serviceLimit/store.js create mode 100644 src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json create mode 100644 src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json diff --git a/packages/ui/src/infobox/index.tsx b/packages/ui/src/infobox/index.tsx index 9066a623e..09fc4596a 100644 --- a/packages/ui/src/infobox/index.tsx +++ b/packages/ui/src/infobox/index.tsx @@ -48,13 +48,13 @@ const styles = (theme: Theme) => ({ position: 'relative', overflow: 'hidden', height: 'auto', + marginBottom: 30, }, infobox: { alignItems: 'center', borderRadius: theme.borderRadiusSmall, display: 'flex', height: 'auto', - marginBottom: 30, padding: '15px 20px', top: 0, transition: 'all 0.5s', diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js index 00cd725cf..862bd4a27 100644 --- a/src/components/settings/recipes/RecipesDashboard.js +++ b/src/components/settings/recipes/RecipesDashboard.js @@ -10,6 +10,7 @@ import RecipeItem from './RecipeItem'; import Loader from '../../ui/Loader'; import Appear from '../../ui/effects/Appear'; import { FRANZ_SERVICE_REQUEST } from '../../../config'; +import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; const messages = defineMessages({ headline: { @@ -86,6 +87,7 @@ export default @observer class RecipesDashboard extends Component {

{intl.formatMessage(messages.headline)}

+
{serviceStatus.length > 0 && serviceStatus.includes('created') && ( diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js index 4ba2eb844..c089a1582 100644 --- a/src/components/settings/services/EditServiceForm.js +++ b/src/components/settings/services/EditServiceForm.js @@ -17,6 +17,8 @@ import ImageUpload from '../../ui/ImageUpload'; import Select from '../../ui/Select'; import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; +import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; +import { serviceLimitStore } from '../../../features/serviceLimit'; const messages = defineMessages({ saveService: { @@ -252,6 +254,7 @@ export default @observer class EditServiceForm extends Component { )}
+
this.submit(e)} id="form">
@@ -418,7 +421,7 @@ export default @observer class EditServiceForm extends Component { type="submit" label={intl.formatMessage(messages.saveService)} htmlForm="form" - disabled={action !== 'edit' && form.isPristine && requiresUserInput} + disabled={action !== 'edit' && ((form.isPristine && requiresUserInput) || serviceLimitStore.userHasReachedServiceLimit)} /> )}
diff --git a/src/components/settings/services/ServicesDashboard.js b/src/components/settings/services/ServicesDashboard.js index 53bae12df..78038e86a 100644 --- a/src/components/settings/services/ServicesDashboard.js +++ b/src/components/settings/services/ServicesDashboard.js @@ -9,6 +9,7 @@ import Infobox from '../../ui/Infobox'; import Loader from '../../ui/Loader'; import ServiceItem from './ServiceItem'; import Appear from '../../ui/effects/Appear'; +import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; const messages = defineMessages({ headline: { @@ -91,6 +92,7 @@ export default @observer class ServicesDashboard extends Component {

{intl.formatMessage(messages.headline)}

+
{!isLoading && ( ({ + container: { + height: 'auto', + background: theme.styleTypes.primary.accent, + color: theme.styleTypes.primary.contrast, + borderRadius: 0, + marginBottom: 0, + + '& button': { + color: theme.styleTypes.primary.contrast, + }, + }, +}); + + +@inject('stores', 'actions') @injectSheet(styles) @observer +class LimitReachedInfobox extends Component { + static propTypes = { + classes: PropTypes.object.isRequired, + stores: PropTypes.object.isRequired, + actions: PropTypes.object.isRequired, + }; + + static contextTypes = { + intl: intlShape, + }; + + render() { + const { classes, stores, actions } = this.props; + const { intl } = this.context; + + const { + serviceLimit, + } = stores; + + if (!serviceLimit.userHasReachedServiceLimit) return null; + + return ( + { + actions.ui.openSettings({ path: 'user' }); + gaEvent('Service Limit', 'upgrade', 'Upgrade account'); + }} + > + {intl.formatMessage(messages.limitReached, { amount: serviceLimit.serviceCount, limit: serviceLimit.serviceLimit })} + + ); + } +} + +export default LimitReachedInfobox; diff --git a/src/features/serviceLimit/index.js b/src/features/serviceLimit/index.js new file mode 100644 index 000000000..76f996195 --- /dev/null +++ b/src/features/serviceLimit/index.js @@ -0,0 +1,33 @@ +import { reaction } from 'mobx'; +import { ServiceLimitStore } from './store'; + +const debug = require('debug')('Franz:feature:serviceLimit'); + +export const DEFAULT_SERVICE_LIMIT = 3; + +let store = null; + +export const serviceLimitStore = new ServiceLimitStore(); + +export default function initServiceLimit(stores, actions) { + const { features } = stores; + + // Toggle serviceLimit feature + reaction( + () => ( + features.features.hasServiceLimit + ), + (isEnabled) => { + if (isEnabled) { + debug('Initializing `serviceLimit` feature'); + store = serviceLimitStore.start(stores, actions); + } else if (store) { + debug('Disabling `serviceLimit` feature'); + serviceLimitStore.stop(); + } + }, + { + fireImmediately: true, + }, + ); +} diff --git a/src/features/serviceLimit/store.js b/src/features/serviceLimit/store.js new file mode 100644 index 000000000..752f71371 --- /dev/null +++ b/src/features/serviceLimit/store.js @@ -0,0 +1,41 @@ +import { computed, observable } from 'mobx'; +import { FeatureStore } from '../utils/FeatureStore'; +import { DEFAULT_SERVICE_LIMIT } from '.'; + +const debug = require('debug')('Franz:feature:serviceLimit:store'); + +export class ServiceLimitStore extends FeatureStore { + @observable isServiceLimitEnabled = false; + + start(stores, actions) { + debug('start'); + this.stores = stores; + this.actions = actions; + + this.isServiceLimitEnabled = true; + } + + stop() { + super.stop(); + + this.isServiceLimitEnabled = false; + } + + @computed get userHasReachedServiceLimit() { + if (!this.isServiceLimitEnabled) return false; + + const { user } = this.stores; + + return !user.isPremium && this.serviceCount >= this.serviceLimit; + } + + @computed get serviceLimit() { + return this.stores.features.features.serviceLimitCount || DEFAULT_SERVICE_LIMIT; + } + + @computed get serviceCount() { + return this.stores.services.all.length; + } +} + +export default ServiceLimitStore; diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json index 632eb38fd..9980274d3 100644 --- a/src/i18n/locales/defaultMessages.json +++ b/src/i18n/locales/defaultMessages.json @@ -1411,104 +1411,104 @@ "defaultMessage": "!!!Available Services", "end": { "column": 3, - "line": 18 + "line": 19 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.headline", "start": { "column": 12, - "line": 15 + "line": 16 } }, { "defaultMessage": "!!!Search service", "end": { "column": 3, - "line": 22 + "line": 23 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.searchService", "start": { "column": 17, - "line": 19 + "line": 20 } }, { "defaultMessage": "!!!Most popular", "end": { "column": 3, - "line": 26 + "line": 27 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.mostPopular", "start": { "column": 22, - "line": 23 + "line": 24 } }, { "defaultMessage": "!!!All services", "end": { "column": 3, - "line": 30 + "line": 31 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.all", "start": { "column": 14, - "line": 27 + "line": 28 } }, { "defaultMessage": "!!!Development", "end": { "column": 3, - "line": 34 + "line": 35 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.dev", "start": { "column": 14, - "line": 31 + "line": 32 } }, { "defaultMessage": "!!!Sorry, but no service matched your search term.", "end": { "column": 3, - "line": 38 + "line": 39 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.nothingFound", "start": { "column": 16, - "line": 35 + "line": 36 } }, { "defaultMessage": "!!!Service successfully added", "end": { "column": 3, - "line": 42 + "line": 43 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.servicesSuccessfulAddedInfo", "start": { "column": 31, - "line": 39 + "line": 40 } }, { "defaultMessage": "!!!Missing a service?", "end": { "column": 3, - "line": 46 + "line": 47 }, "file": "src/components/settings/recipes/RecipesDashboard.js", "id": "settings.recipes.missingService", "start": { "column": 18, - "line": 43 + "line": 44 } } ], @@ -1520,286 +1520,286 @@ "defaultMessage": "!!!Save service", "end": { "column": 3, - "line": 25 + "line": 26 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.saveButton", "start": { "column": 15, - "line": 22 + "line": 23 } }, { "defaultMessage": "!!!Delete Service", "end": { "column": 3, - "line": 29 + "line": 30 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.deleteButton", "start": { "column": 17, - "line": 26 + "line": 27 } }, { "defaultMessage": "!!!Available services", "end": { "column": 3, - "line": 33 + "line": 34 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.availableServices", "start": { "column": 21, - "line": 30 + "line": 31 } }, { "defaultMessage": "!!!Your services", "end": { "column": 3, - "line": 37 + "line": 38 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.yourServices", "start": { "column": 16, - "line": 34 + "line": 35 } }, { "defaultMessage": "!!!Add {name}", "end": { "column": 3, - "line": 41 + "line": 42 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.addServiceHeadline", "start": { "column": 22, - "line": 38 + "line": 39 } }, { "defaultMessage": "!!!Edit {name}", "end": { "column": 3, - "line": 45 + "line": 46 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.editServiceHeadline", "start": { "column": 23, - "line": 42 + "line": 43 } }, { "defaultMessage": "!!!Hosted", "end": { "column": 3, - "line": 49 + "line": 50 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.tabHosted", "start": { "column": 13, - "line": 46 + "line": 47 } }, { "defaultMessage": "!!!Self hosted ⭐️", "end": { "column": 3, - "line": 53 + "line": 54 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.tabOnPremise", "start": { "column": 16, - "line": 50 + "line": 51 } }, { "defaultMessage": "!!!Use the hosted {name} service.", "end": { "column": 3, - "line": 57 + "line": 58 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.useHostedService", "start": { "column": 20, - "line": 54 + "line": 55 } }, { "defaultMessage": "!!!Could not validate custom {name} server.", "end": { "column": 3, - "line": 61 + "line": 62 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.customUrlValidationError", "start": { "column": 28, - "line": 58 + "line": 59 } }, { "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", "end": { "column": 3, - "line": 65 + "line": 66 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.customUrlPremiumInfo", "start": { "column": 24, - "line": 62 + "line": 63 } }, { "defaultMessage": "!!!Upgrade your account", "end": { "column": 3, - "line": 69 + "line": 70 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.customUrlUpgradeAccount", "start": { "column": 27, - "line": 66 + "line": 67 } }, { "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", "end": { "column": 3, - "line": 73 + "line": 74 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.indirectMessageInfo", "start": { "column": 23, - "line": 70 + "line": 71 } }, { "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", "end": { "column": 3, - "line": 77 + "line": 78 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.isMutedInfo", "start": { "column": 15, - "line": 74 + "line": 75 } }, { "defaultMessage": "!!!Notifications", "end": { "column": 3, - "line": 81 + "line": 82 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.headlineNotifications", "start": { "column": 25, - "line": 78 + "line": 79 } }, { "defaultMessage": "!!!Unread message badges", "end": { "column": 3, - "line": 85 + "line": 86 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.headlineBadges", "start": { "column": 18, - "line": 82 + "line": 83 } }, { "defaultMessage": "!!!General", "end": { "column": 3, - "line": 89 + "line": 90 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.headlineGeneral", "start": { "column": 19, - "line": 86 + "line": 87 } }, { "defaultMessage": "!!!Delete", "end": { "column": 3, - "line": 93 + "line": 94 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.iconDelete", "start": { "column": 14, - "line": 90 + "line": 91 } }, { "defaultMessage": "!!!Drop your image, or click here", "end": { "column": 3, - "line": 97 + "line": 98 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.iconUpload", "start": { "column": 14, - "line": 94 + "line": 95 } }, { "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", "end": { "column": 3, - "line": 101 + "line": 102 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.proxy.headline", "start": { "column": 17, - "line": 98 + "line": 99 } }, { "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", "end": { "column": 3, - "line": 105 + "line": 106 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.proxy.restartInfo", "start": { "column": 20, - "line": 102 + "line": 103 } }, { "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", "end": { "column": 3, - "line": 109 + "line": 110 }, "file": "src/components/settings/services/EditServiceForm.js", "id": "settings.service.form.proxy.info", "start": { "column": 13, - "line": 106 + "line": 107 } } ], @@ -1912,117 +1912,117 @@ "defaultMessage": "!!!Your services", "end": { "column": 3, - "line": 17 + "line": 18 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.headline", "start": { "column": 12, - "line": 14 + "line": 15 } }, { "defaultMessage": "!!!Search service", "end": { "column": 3, - "line": 21 + "line": 22 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.searchService", "start": { "column": 17, - "line": 18 + "line": 19 } }, { "defaultMessage": "!!!You haven't added any services yet.", "end": { "column": 3, - "line": 25 + "line": 26 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.noServicesAdded", "start": { "column": 19, - "line": 22 + "line": 23 } }, { "defaultMessage": "!!!Sorry, but no service matched your search term.", "end": { "column": 3, - "line": 29 + "line": 30 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.recipes.nothingFound", "start": { "column": 18, - "line": 26 + "line": 27 } }, { "defaultMessage": "!!!Discover services", "end": { "column": 3, - "line": 33 + "line": 34 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.discoverServices", "start": { "column": 20, - "line": 30 + "line": 31 } }, { "defaultMessage": "!!!Could not load your services", "end": { "column": 3, - "line": 37 + "line": 38 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.servicesRequestFailed", "start": { "column": 25, - "line": 34 + "line": 35 } }, { "defaultMessage": "!!!Try again", "end": { "column": 3, - "line": 41 + "line": 42 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.account.tryReloadServices", "start": { "column": 21, - "line": 38 + "line": 39 } }, { "defaultMessage": "!!!Your changes have been saved", "end": { "column": 3, - "line": 45 + "line": 46 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.updatedInfo", "start": { "column": 15, - "line": 42 + "line": 43 } }, { "defaultMessage": "!!!Service has been deleted", "end": { "column": 3, - "line": 49 + "line": 50 }, "file": "src/components/settings/services/ServicesDashboard.js", "id": "settings.services.deletedInfo", "start": { "column": 15, - "line": 46 + "line": 47 } } ], @@ -3263,6 +3263,55 @@ ], "path": "src/features/delayApp/Component.json" }, + { + "descriptors": [ + { + "defaultMessage": "!!!Changes in Franz {version}", + "end": { + "column": 3, + "line": 23 + }, + "file": "src/features/serviceLimit/components/AnnouncementScreen.js", + "id": "feature.announcements.changelog.headline", + "start": { + "column": 12, + "line": 20 + } + } + ], + "path": "src/features/serviceLimit/components/AnnouncementScreen.json" + }, + { + "descriptors": [ + { + "defaultMessage": "!!!You have added {amount} of {amount} services. Please upgrade your account to add more services.", + "end": { + "column": 3, + "line": 16 + }, + "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", + "id": "feature.serviceLimit.limitReached", + "start": { + "column": 16, + "line": 13 + } + }, + { + "defaultMessage": "!!!Upgrade account", + "end": { + "column": 3, + "line": 20 + }, + "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", + "id": "premiumFeature.button.upgradeAccount", + "start": { + "column": 10, + "line": 17 + } + } + ], + "path": "src/features/serviceLimit/components/LimitReachedInfobox.json" + }, { "descriptors": [ { diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index 6c2759dcc..1bc8fd2bf 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -5,6 +5,7 @@ "feature.delayApp.action": "Get a Franz Supporter License", "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", "feature.delayApp.text": "Franz will continue in {seconds} seconds.", + "feature.serviceLimit.limitReached": "You have added {amount} of {limit} services. Please upgrade your account to add more services.", "feature.shareFranz.action.email": "Send as email", "feature.shareFranz.action.facebook": "Share on Facebook", "feature.shareFranz.action.twitter": "Share on Twitter", @@ -328,4 +329,4 @@ "workspaceDrawer.workspaceFeatureInfo": "

Franz Workspaces let you focus on what’s important right now. Set up different sets of services and easily switch between them at any time.

You decide which services you need when and where, so we can help you stay on top of your game - or easily switch off from work whenever you want.

", "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", "workspaces.switchingIndicator.switchingTo": "Switching to" -} \ No newline at end of file +} diff --git a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json index 7d9ed3283..07eada1dc 100644 --- a/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json +++ b/src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Available Services", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 15, + "line": 16, "column": 12 }, "end": { - "line": 18, + "line": 19, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Search service", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 19, + "line": 20, "column": 17 }, "end": { - "line": 22, + "line": 23, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Most popular", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 23, + "line": 24, "column": 22 }, "end": { - "line": 26, + "line": 27, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!All services", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 27, + "line": 28, "column": 14 }, "end": { - "line": 30, + "line": 31, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Development", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 31, + "line": 32, "column": 14 }, "end": { - "line": 34, + "line": 35, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Sorry, but no service matched your search term.", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 35, + "line": 36, "column": 16 }, "end": { - "line": 38, + "line": 39, "column": 3 } }, @@ -82,11 +82,11 @@ "defaultMessage": "!!!Service successfully added", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 39, + "line": 40, "column": 31 }, "end": { - "line": 42, + "line": 43, "column": 3 } }, @@ -95,11 +95,11 @@ "defaultMessage": "!!!Missing a service?", "file": "src/components/settings/recipes/RecipesDashboard.js", "start": { - "line": 43, + "line": 44, "column": 18 }, "end": { - "line": 46, + "line": 47, "column": 3 } } diff --git a/src/i18n/messages/src/components/settings/services/EditServiceForm.json b/src/i18n/messages/src/components/settings/services/EditServiceForm.json index 42b741b7a..e66db807d 100644 --- a/src/i18n/messages/src/components/settings/services/EditServiceForm.json +++ b/src/i18n/messages/src/components/settings/services/EditServiceForm.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Save service", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 22, + "line": 24, "column": 15 }, "end": { - "line": 25, + "line": 27, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Delete Service", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 26, + "line": 28, "column": 17 }, "end": { - "line": 29, + "line": 31, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!Available services", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 30, + "line": 32, "column": 21 }, "end": { - "line": 33, + "line": 35, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Your services", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 34, + "line": 36, "column": 16 }, "end": { - "line": 37, + "line": 39, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Add {name}", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 38, + "line": 40, "column": 22 }, "end": { - "line": 41, + "line": 43, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Edit {name}", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 42, + "line": 44, "column": 23 }, "end": { - "line": 45, + "line": 47, "column": 3 } }, @@ -82,11 +82,11 @@ "defaultMessage": "!!!Hosted", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 46, + "line": 48, "column": 13 }, "end": { - "line": 49, + "line": 51, "column": 3 } }, @@ -95,11 +95,11 @@ "defaultMessage": "!!!Self hosted ⭐️", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 50, + "line": 52, "column": 16 }, "end": { - "line": 53, + "line": 55, "column": 3 } }, @@ -108,11 +108,11 @@ "defaultMessage": "!!!Use the hosted {name} service.", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 54, + "line": 56, "column": 20 }, "end": { - "line": 57, + "line": 59, "column": 3 } }, @@ -121,11 +121,11 @@ "defaultMessage": "!!!Could not validate custom {name} server.", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 58, + "line": 60, "column": 28 }, "end": { - "line": 61, + "line": 63, "column": 3 } }, @@ -134,11 +134,11 @@ "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 62, + "line": 64, "column": 24 }, "end": { - "line": 65, + "line": 67, "column": 3 } }, @@ -147,11 +147,11 @@ "defaultMessage": "!!!Upgrade your account", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 66, + "line": 68, "column": 27 }, "end": { - "line": 69, + "line": 71, "column": 3 } }, @@ -160,11 +160,11 @@ "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 70, + "line": 72, "column": 23 }, "end": { - "line": 73, + "line": 75, "column": 3 } }, @@ -173,11 +173,11 @@ "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 74, + "line": 76, "column": 15 }, "end": { - "line": 77, + "line": 79, "column": 3 } }, @@ -186,11 +186,11 @@ "defaultMessage": "!!!Notifications", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 78, + "line": 80, "column": 25 }, "end": { - "line": 81, + "line": 83, "column": 3 } }, @@ -199,11 +199,11 @@ "defaultMessage": "!!!Unread message badges", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 82, + "line": 84, "column": 18 }, "end": { - "line": 85, + "line": 87, "column": 3 } }, @@ -212,11 +212,11 @@ "defaultMessage": "!!!General", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 86, + "line": 88, "column": 19 }, "end": { - "line": 89, + "line": 91, "column": 3 } }, @@ -225,11 +225,11 @@ "defaultMessage": "!!!Delete", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 90, + "line": 92, "column": 14 }, "end": { - "line": 93, + "line": 95, "column": 3 } }, @@ -238,11 +238,11 @@ "defaultMessage": "!!!Drop your image, or click here", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 94, + "line": 96, "column": 14 }, "end": { - "line": 97, + "line": 99, "column": 3 } }, @@ -251,11 +251,11 @@ "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 98, + "line": 100, "column": 17 }, "end": { - "line": 101, + "line": 103, "column": 3 } }, @@ -264,11 +264,11 @@ "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 102, + "line": 104, "column": 20 }, "end": { - "line": 105, + "line": 107, "column": 3 } }, @@ -277,11 +277,11 @@ "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", "file": "src/components/settings/services/EditServiceForm.js", "start": { - "line": 106, + "line": 108, "column": 13 }, "end": { - "line": 109, + "line": 111, "column": 3 } } diff --git a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json b/src/i18n/messages/src/components/settings/services/ServicesDashboard.json index 3803c6512..fa661ea2f 100644 --- a/src/i18n/messages/src/components/settings/services/ServicesDashboard.json +++ b/src/i18n/messages/src/components/settings/services/ServicesDashboard.json @@ -4,11 +4,11 @@ "defaultMessage": "!!!Your services", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 14, + "line": 15, "column": 12 }, "end": { - "line": 17, + "line": 18, "column": 3 } }, @@ -17,11 +17,11 @@ "defaultMessage": "!!!Search service", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 18, + "line": 19, "column": 17 }, "end": { - "line": 21, + "line": 22, "column": 3 } }, @@ -30,11 +30,11 @@ "defaultMessage": "!!!You haven't added any services yet.", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 22, + "line": 23, "column": 19 }, "end": { - "line": 25, + "line": 26, "column": 3 } }, @@ -43,11 +43,11 @@ "defaultMessage": "!!!Sorry, but no service matched your search term.", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 26, + "line": 27, "column": 18 }, "end": { - "line": 29, + "line": 30, "column": 3 } }, @@ -56,11 +56,11 @@ "defaultMessage": "!!!Discover services", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 30, + "line": 31, "column": 20 }, "end": { - "line": 33, + "line": 34, "column": 3 } }, @@ -69,11 +69,11 @@ "defaultMessage": "!!!Could not load your services", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 34, + "line": 35, "column": 25 }, "end": { - "line": 37, + "line": 38, "column": 3 } }, @@ -82,11 +82,11 @@ "defaultMessage": "!!!Try again", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 38, + "line": 39, "column": 21 }, "end": { - "line": 41, + "line": 42, "column": 3 } }, @@ -95,11 +95,11 @@ "defaultMessage": "!!!Your changes have been saved", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 42, + "line": 43, "column": 15 }, "end": { - "line": 45, + "line": 46, "column": 3 } }, @@ -108,11 +108,11 @@ "defaultMessage": "!!!Service has been deleted", "file": "src/components/settings/services/ServicesDashboard.js", "start": { - "line": 46, + "line": 47, "column": 15 }, "end": { - "line": 49, + "line": 50, "column": 3 } } diff --git a/src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json b/src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json new file mode 100644 index 000000000..e6e3cef99 --- /dev/null +++ b/src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json @@ -0,0 +1,15 @@ +[ + { + "id": "feature.announcements.changelog.headline", + "defaultMessage": "!!!Changes in Franz {version}", + "file": "src/features/serviceLimit/components/AnnouncementScreen.js", + "start": { + "line": 20, + "column": 12 + }, + "end": { + "line": 23, + "column": 3 + } + } +] \ No newline at end of file diff --git a/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json b/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json new file mode 100644 index 000000000..df5bc03e8 --- /dev/null +++ b/src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json @@ -0,0 +1,28 @@ +[ + { + "id": "feature.serviceLimit.limitReached", + "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.", + "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", + "start": { + "line": 11, + "column": 16 + }, + "end": { + "line": 14, + "column": 3 + } + }, + { + "id": "premiumFeature.button.upgradeAccount", + "defaultMessage": "!!!Upgrade account", + "file": "src/features/serviceLimit/components/LimitReachedInfobox.js", + "start": { + "line": 15, + "column": 10 + }, + "end": { + "line": 18, + "column": 3 + } + } +] \ No newline at end of file diff --git a/src/stores/FeaturesStore.js b/src/stores/FeaturesStore.js index e7832088b..1ac05d3b9 100644 --- a/src/stores/FeaturesStore.js +++ b/src/stores/FeaturesStore.js @@ -16,6 +16,7 @@ import workspaces from '../features/workspaces'; import shareFranz from '../features/shareFranz'; import announcements from '../features/announcements'; import settingsWS from '../features/settingsWS'; +import serviceLimit from '../features/serviceLimit'; import { DEFAULT_FEATURES_CONFIG } from '../config'; @@ -75,5 +76,6 @@ export default class FeaturesStore extends Store { shareFranz(this.stores, this.actions); announcements(this.stores, this.actions); settingsWS(this.stores, this.actions); + serviceLimit(this.stores, this.actions); } } diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 13f929c2f..349de2c9b 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js @@ -13,6 +13,7 @@ import CachedRequest from './lib/CachedRequest'; import { matchRoute } from '../helpers/routing-helpers'; import { gaEvent, statsEvent } from '../lib/analytics'; import { workspaceStore } from '../features/workspaces'; +import { serviceLimitStore } from '../features/serviceLimit'; const debug = require('debug')('Franz:ServiceStore'); @@ -164,6 +165,8 @@ export default class ServicesStore extends Store { // Actions @action async _createService({ recipeId, serviceData, redirect = true }) { + if (serviceLimitStore.userHasReachedServiceLimit) return; + const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); const response = await this.createServiceRequest.execute(recipeId, data)._promise; diff --git a/src/stores/index.js b/src/stores/index.js index 1912418a2..ff01a3dd3 100644 --- a/src/stores/index.js +++ b/src/stores/index.js @@ -12,6 +12,7 @@ import RequestStore from './RequestStore'; import GlobalErrorStore from './GlobalErrorStore'; import { workspaceStore } from '../features/workspaces'; import { announcementsStore } from '../features/announcements'; +import { serviceLimitStore } from '../features/serviceLimit'; export default (api, actions, router) => { const stores = {}; @@ -31,6 +32,7 @@ export default (api, actions, router) => { globalError: new GlobalErrorStore(stores, api, actions), workspaces: workspaceStore, announcements: announcementsStore, + serviceLimit: serviceLimitStore, }); // Initialize all stores Object.keys(stores).forEach((name) => { -- cgit v1.2.3-70-g09d2