aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/ui/src/infobox/index.tsx2
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js2
-rw-r--r--src/components/settings/services/EditServiceForm.js5
-rw-r--r--src/components/settings/services/ServicesDashboard.js2
-rw-r--r--src/features/serviceLimit/components/LimitReachedInfobox.js74
-rw-r--r--src/features/serviceLimit/index.js33
-rw-r--r--src/features/serviceLimit/store.js41
-rw-r--r--src/i18n/locales/defaultMessages.json205
-rw-r--r--src/i18n/locales/en-US.json3
-rw-r--r--src/i18n/messages/src/components/settings/recipes/RecipesDashboard.json32
-rw-r--r--src/i18n/messages/src/components/settings/services/EditServiceForm.json88
-rw-r--r--src/i18n/messages/src/components/settings/services/ServicesDashboard.json36
-rw-r--r--src/i18n/messages/src/features/serviceLimit/components/AnnouncementScreen.json15
-rw-r--r--src/i18n/messages/src/features/serviceLimit/components/LimitReachedInfobox.json28
-rw-r--r--src/stores/FeaturesStore.js2
-rw-r--r--src/stores/ServicesStore.js3
-rw-r--r--src/stores/index.js2
17 files changed, 414 insertions, 159 deletions
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) => ({
48 position: 'relative', 48 position: 'relative',
49 overflow: 'hidden', 49 overflow: 'hidden',
50 height: 'auto', 50 height: 'auto',
51 marginBottom: 30,
51 }, 52 },
52 infobox: { 53 infobox: {
53 alignItems: 'center', 54 alignItems: 'center',
54 borderRadius: theme.borderRadiusSmall, 55 borderRadius: theme.borderRadiusSmall,
55 display: 'flex', 56 display: 'flex',
56 height: 'auto', 57 height: 'auto',
57 marginBottom: 30,
58 padding: '15px 20px', 58 padding: '15px 20px',
59 top: 0, 59 top: 0,
60 transition: 'all 0.5s', 60 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';
10import Loader from '../../ui/Loader'; 10import Loader from '../../ui/Loader';
11import Appear from '../../ui/effects/Appear'; 11import Appear from '../../ui/effects/Appear';
12import { FRANZ_SERVICE_REQUEST } from '../../../config'; 12import { FRANZ_SERVICE_REQUEST } from '../../../config';
13import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
13 14
14const messages = defineMessages({ 15const messages = defineMessages({
15 headline: { 16 headline: {
@@ -86,6 +87,7 @@ export default @observer class RecipesDashboard extends Component {
86 <div className="settings__header"> 87 <div className="settings__header">
87 <h1>{intl.formatMessage(messages.headline)}</h1> 88 <h1>{intl.formatMessage(messages.headline)}</h1>
88 </div> 89 </div>
90 <LimitReachedInfobox />
89 <div className="settings__body recipes"> 91 <div className="settings__body recipes">
90 {serviceStatus.length > 0 && serviceStatus.includes('created') && ( 92 {serviceStatus.length > 0 && serviceStatus.includes('created') && (
91 <Appear> 93 <Appear>
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';
17import Select from '../../ui/Select'; 17import Select from '../../ui/Select';
18 18
19import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; 19import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
20import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
21import { serviceLimitStore } from '../../../features/serviceLimit';
20 22
21const messages = defineMessages({ 23const messages = defineMessages({
22 saveService: { 24 saveService: {
@@ -252,6 +254,7 @@ export default @observer class EditServiceForm extends Component {
252 )} 254 )}
253 </span> 255 </span>
254 </div> 256 </div>
257 <LimitReachedInfobox />
255 <div className="settings__body"> 258 <div className="settings__body">
256 <form onSubmit={e => this.submit(e)} id="form"> 259 <form onSubmit={e => this.submit(e)} id="form">
257 <div className="service-name"> 260 <div className="service-name">
@@ -418,7 +421,7 @@ export default @observer class EditServiceForm extends Component {
418 type="submit" 421 type="submit"
419 label={intl.formatMessage(messages.saveService)} 422 label={intl.formatMessage(messages.saveService)}
420 htmlForm="form" 423 htmlForm="form"
421 disabled={action !== 'edit' && form.isPristine && requiresUserInput} 424 disabled={action !== 'edit' && ((form.isPristine && requiresUserInput) || serviceLimitStore.userHasReachedServiceLimit)}
422 /> 425 />
423 )} 426 )}
424 </div> 427 </div>
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';
9import Loader from '../../ui/Loader'; 9import Loader from '../../ui/Loader';
10import ServiceItem from './ServiceItem'; 10import ServiceItem from './ServiceItem';
11import Appear from '../../ui/effects/Appear'; 11import Appear from '../../ui/effects/Appear';
12import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
12 13
13const messages = defineMessages({ 14const messages = defineMessages({
14 headline: { 15 headline: {
@@ -91,6 +92,7 @@ export default @observer class ServicesDashboard extends Component {
91 <div className="settings__header"> 92 <div className="settings__header">
92 <h1>{intl.formatMessage(messages.headline)}</h1> 93 <h1>{intl.formatMessage(messages.headline)}</h1>
93 </div> 94 </div>
95 <LimitReachedInfobox />
94 <div className="settings__body"> 96 <div className="settings__body">
95 {!isLoading && ( 97 {!isLoading && (
96 <SearchInput 98 <SearchInput
diff --git a/src/features/serviceLimit/components/LimitReachedInfobox.js b/src/features/serviceLimit/components/LimitReachedInfobox.js
new file mode 100644
index 000000000..ee0d7cb27
--- /dev/null
+++ b/src/features/serviceLimit/components/LimitReachedInfobox.js
@@ -0,0 +1,74 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { inject, observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss';
6import { Infobox } from '@meetfranz/ui';
7
8import { gaEvent } from '../../../lib/analytics';
9
10const messages = defineMessages({
11 limitReached: {
12 id: 'feature.serviceLimit.limitReached',
13 defaultMessage: '!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.',
14 },
15 action: {
16 id: 'premiumFeature.button.upgradeAccount',
17 defaultMessage: '!!!Upgrade account',
18 },
19});
20
21const styles = theme => ({
22 container: {
23 height: 'auto',
24 background: theme.styleTypes.primary.accent,
25 color: theme.styleTypes.primary.contrast,
26 borderRadius: 0,
27 marginBottom: 0,
28
29 '& button': {
30 color: theme.styleTypes.primary.contrast,
31 },
32 },
33});
34
35
36@inject('stores', 'actions') @injectSheet(styles) @observer
37class LimitReachedInfobox extends Component {
38 static propTypes = {
39 classes: PropTypes.object.isRequired,
40 stores: PropTypes.object.isRequired,
41 actions: PropTypes.object.isRequired,
42 };
43
44 static contextTypes = {
45 intl: intlShape,
46 };
47
48 render() {
49 const { classes, stores, actions } = this.props;
50 const { intl } = this.context;
51
52 const {
53 serviceLimit,
54 } = stores;
55
56 if (!serviceLimit.userHasReachedServiceLimit) return null;
57
58 return (
59 <Infobox
60 icon="mdiInformation"
61 className={classes.container}
62 ctaLabel={intl.formatMessage(messages.action)}
63 ctaOnClick={() => {
64 actions.ui.openSettings({ path: 'user' });
65 gaEvent('Service Limit', 'upgrade', 'Upgrade account');
66 }}
67 >
68 {intl.formatMessage(messages.limitReached, { amount: serviceLimit.serviceCount, limit: serviceLimit.serviceLimit })}
69 </Infobox>
70 );
71 }
72}
73
74export 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 @@
1import { reaction } from 'mobx';
2import { ServiceLimitStore } from './store';
3
4const debug = require('debug')('Franz:feature:serviceLimit');
5
6export const DEFAULT_SERVICE_LIMIT = 3;
7
8let store = null;
9
10export const serviceLimitStore = new ServiceLimitStore();
11
12export default function initServiceLimit(stores, actions) {
13 const { features } = stores;
14
15 // Toggle serviceLimit feature
16 reaction(
17 () => (
18 features.features.hasServiceLimit
19 ),
20 (isEnabled) => {
21 if (isEnabled) {
22 debug('Initializing `serviceLimit` feature');
23 store = serviceLimitStore.start(stores, actions);
24 } else if (store) {
25 debug('Disabling `serviceLimit` feature');
26 serviceLimitStore.stop();
27 }
28 },
29 {
30 fireImmediately: true,
31 },
32 );
33}
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 @@
1import { computed, observable } from 'mobx';
2import { FeatureStore } from '../utils/FeatureStore';
3import { DEFAULT_SERVICE_LIMIT } from '.';
4
5const debug = require('debug')('Franz:feature:serviceLimit:store');
6
7export class ServiceLimitStore extends FeatureStore {
8 @observable isServiceLimitEnabled = false;
9
10 start(stores, actions) {
11 debug('start');
12 this.stores = stores;
13 this.actions = actions;
14
15 this.isServiceLimitEnabled = true;
16 }
17
18 stop() {
19 super.stop();
20
21 this.isServiceLimitEnabled = false;
22 }
23
24 @computed get userHasReachedServiceLimit() {
25 if (!this.isServiceLimitEnabled) return false;
26
27 const { user } = this.stores;
28
29 return !user.isPremium && this.serviceCount >= this.serviceLimit;
30 }
31
32 @computed get serviceLimit() {
33 return this.stores.features.features.serviceLimitCount || DEFAULT_SERVICE_LIMIT;
34 }
35
36 @computed get serviceCount() {
37 return this.stores.services.all.length;
38 }
39}
40
41export 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 @@
1411 "defaultMessage": "!!!Available Services", 1411 "defaultMessage": "!!!Available Services",
1412 "end": { 1412 "end": {
1413 "column": 3, 1413 "column": 3,
1414 "line": 18 1414 "line": 19
1415 }, 1415 },
1416 "file": "src/components/settings/recipes/RecipesDashboard.js", 1416 "file": "src/components/settings/recipes/RecipesDashboard.js",
1417 "id": "settings.recipes.headline", 1417 "id": "settings.recipes.headline",
1418 "start": { 1418 "start": {
1419 "column": 12, 1419 "column": 12,
1420 "line": 15 1420 "line": 16
1421 } 1421 }
1422 }, 1422 },
1423 { 1423 {
1424 "defaultMessage": "!!!Search service", 1424 "defaultMessage": "!!!Search service",
1425 "end": { 1425 "end": {
1426 "column": 3, 1426 "column": 3,
1427 "line": 22 1427 "line": 23
1428 }, 1428 },
1429 "file": "src/components/settings/recipes/RecipesDashboard.js", 1429 "file": "src/components/settings/recipes/RecipesDashboard.js",
1430 "id": "settings.searchService", 1430 "id": "settings.searchService",
1431 "start": { 1431 "start": {
1432 "column": 17, 1432 "column": 17,
1433 "line": 19 1433 "line": 20
1434 } 1434 }
1435 }, 1435 },
1436 { 1436 {
1437 "defaultMessage": "!!!Most popular", 1437 "defaultMessage": "!!!Most popular",
1438 "end": { 1438 "end": {
1439 "column": 3, 1439 "column": 3,
1440 "line": 26 1440 "line": 27
1441 }, 1441 },
1442 "file": "src/components/settings/recipes/RecipesDashboard.js", 1442 "file": "src/components/settings/recipes/RecipesDashboard.js",
1443 "id": "settings.recipes.mostPopular", 1443 "id": "settings.recipes.mostPopular",
1444 "start": { 1444 "start": {
1445 "column": 22, 1445 "column": 22,
1446 "line": 23 1446 "line": 24
1447 } 1447 }
1448 }, 1448 },
1449 { 1449 {
1450 "defaultMessage": "!!!All services", 1450 "defaultMessage": "!!!All services",
1451 "end": { 1451 "end": {
1452 "column": 3, 1452 "column": 3,
1453 "line": 30 1453 "line": 31
1454 }, 1454 },
1455 "file": "src/components/settings/recipes/RecipesDashboard.js", 1455 "file": "src/components/settings/recipes/RecipesDashboard.js",
1456 "id": "settings.recipes.all", 1456 "id": "settings.recipes.all",
1457 "start": { 1457 "start": {
1458 "column": 14, 1458 "column": 14,
1459 "line": 27 1459 "line": 28
1460 } 1460 }
1461 }, 1461 },
1462 { 1462 {
1463 "defaultMessage": "!!!Development", 1463 "defaultMessage": "!!!Development",
1464 "end": { 1464 "end": {
1465 "column": 3, 1465 "column": 3,
1466 "line": 34 1466 "line": 35
1467 }, 1467 },
1468 "file": "src/components/settings/recipes/RecipesDashboard.js", 1468 "file": "src/components/settings/recipes/RecipesDashboard.js",
1469 "id": "settings.recipes.dev", 1469 "id": "settings.recipes.dev",
1470 "start": { 1470 "start": {
1471 "column": 14, 1471 "column": 14,
1472 "line": 31 1472 "line": 32
1473 } 1473 }
1474 }, 1474 },
1475 { 1475 {
1476 "defaultMessage": "!!!Sorry, but no service matched your search term.", 1476 "defaultMessage": "!!!Sorry, but no service matched your search term.",
1477 "end": { 1477 "end": {
1478 "column": 3, 1478 "column": 3,
1479 "line": 38 1479 "line": 39
1480 }, 1480 },
1481 "file": "src/components/settings/recipes/RecipesDashboard.js", 1481 "file": "src/components/settings/recipes/RecipesDashboard.js",
1482 "id": "settings.recipes.nothingFound", 1482 "id": "settings.recipes.nothingFound",
1483 "start": { 1483 "start": {
1484 "column": 16, 1484 "column": 16,
1485 "line": 35 1485 "line": 36
1486 } 1486 }
1487 }, 1487 },
1488 { 1488 {
1489 "defaultMessage": "!!!Service successfully added", 1489 "defaultMessage": "!!!Service successfully added",
1490 "end": { 1490 "end": {
1491 "column": 3, 1491 "column": 3,
1492 "line": 42 1492 "line": 43
1493 }, 1493 },
1494 "file": "src/components/settings/recipes/RecipesDashboard.js", 1494 "file": "src/components/settings/recipes/RecipesDashboard.js",
1495 "id": "settings.recipes.servicesSuccessfulAddedInfo", 1495 "id": "settings.recipes.servicesSuccessfulAddedInfo",
1496 "start": { 1496 "start": {
1497 "column": 31, 1497 "column": 31,
1498 "line": 39 1498 "line": 40
1499 } 1499 }
1500 }, 1500 },
1501 { 1501 {
1502 "defaultMessage": "!!!Missing a service?", 1502 "defaultMessage": "!!!Missing a service?",
1503 "end": { 1503 "end": {
1504 "column": 3, 1504 "column": 3,
1505 "line": 46 1505 "line": 47
1506 }, 1506 },
1507 "file": "src/components/settings/recipes/RecipesDashboard.js", 1507 "file": "src/components/settings/recipes/RecipesDashboard.js",
1508 "id": "settings.recipes.missingService", 1508 "id": "settings.recipes.missingService",
1509 "start": { 1509 "start": {
1510 "column": 18, 1510 "column": 18,
1511 "line": 43 1511 "line": 44
1512 } 1512 }
1513 } 1513 }
1514 ], 1514 ],
@@ -1520,286 +1520,286 @@
1520 "defaultMessage": "!!!Save service", 1520 "defaultMessage": "!!!Save service",
1521 "end": { 1521 "end": {
1522 "column": 3, 1522 "column": 3,
1523 "line": 25 1523 "line": 26
1524 }, 1524 },
1525 "file": "src/components/settings/services/EditServiceForm.js", 1525 "file": "src/components/settings/services/EditServiceForm.js",
1526 "id": "settings.service.form.saveButton", 1526 "id": "settings.service.form.saveButton",
1527 "start": { 1527 "start": {
1528 "column": 15, 1528 "column": 15,
1529 "line": 22 1529 "line": 23
1530 } 1530 }
1531 }, 1531 },
1532 { 1532 {
1533 "defaultMessage": "!!!Delete Service", 1533 "defaultMessage": "!!!Delete Service",
1534 "end": { 1534 "end": {
1535 "column": 3, 1535 "column": 3,
1536 "line": 29 1536 "line": 30
1537 }, 1537 },
1538 "file": "src/components/settings/services/EditServiceForm.js", 1538 "file": "src/components/settings/services/EditServiceForm.js",
1539 "id": "settings.service.form.deleteButton", 1539 "id": "settings.service.form.deleteButton",
1540 "start": { 1540 "start": {
1541 "column": 17, 1541 "column": 17,
1542 "line": 26 1542 "line": 27
1543 } 1543 }
1544 }, 1544 },
1545 { 1545 {
1546 "defaultMessage": "!!!Available services", 1546 "defaultMessage": "!!!Available services",
1547 "end": { 1547 "end": {
1548 "column": 3, 1548 "column": 3,
1549 "line": 33 1549 "line": 34
1550 }, 1550 },
1551 "file": "src/components/settings/services/EditServiceForm.js", 1551 "file": "src/components/settings/services/EditServiceForm.js",
1552 "id": "settings.service.form.availableServices", 1552 "id": "settings.service.form.availableServices",
1553 "start": { 1553 "start": {
1554 "column": 21, 1554 "column": 21,
1555 "line": 30 1555 "line": 31
1556 } 1556 }
1557 }, 1557 },
1558 { 1558 {
1559 "defaultMessage": "!!!Your services", 1559 "defaultMessage": "!!!Your services",
1560 "end": { 1560 "end": {
1561 "column": 3, 1561 "column": 3,
1562 "line": 37 1562 "line": 38
1563 }, 1563 },
1564 "file": "src/components/settings/services/EditServiceForm.js", 1564 "file": "src/components/settings/services/EditServiceForm.js",
1565 "id": "settings.service.form.yourServices", 1565 "id": "settings.service.form.yourServices",
1566 "start": { 1566 "start": {
1567 "column": 16, 1567 "column": 16,
1568 "line": 34 1568 "line": 35
1569 } 1569 }
1570 }, 1570 },
1571 { 1571 {
1572 "defaultMessage": "!!!Add {name}", 1572 "defaultMessage": "!!!Add {name}",
1573 "end": { 1573 "end": {
1574 "column": 3, 1574 "column": 3,
1575 "line": 41 1575 "line": 42
1576 }, 1576 },
1577 "file": "src/components/settings/services/EditServiceForm.js", 1577 "file": "src/components/settings/services/EditServiceForm.js",
1578 "id": "settings.service.form.addServiceHeadline", 1578 "id": "settings.service.form.addServiceHeadline",
1579 "start": { 1579 "start": {
1580 "column": 22, 1580 "column": 22,
1581 "line": 38 1581 "line": 39
1582 } 1582 }
1583 }, 1583 },
1584 { 1584 {
1585 "defaultMessage": "!!!Edit {name}", 1585 "defaultMessage": "!!!Edit {name}",
1586 "end": { 1586 "end": {
1587 "column": 3, 1587 "column": 3,
1588 "line": 45 1588 "line": 46
1589 }, 1589 },
1590 "file": "src/components/settings/services/EditServiceForm.js", 1590 "file": "src/components/settings/services/EditServiceForm.js",
1591 "id": "settings.service.form.editServiceHeadline", 1591 "id": "settings.service.form.editServiceHeadline",
1592 "start": { 1592 "start": {
1593 "column": 23, 1593 "column": 23,
1594 "line": 42 1594 "line": 43
1595 } 1595 }
1596 }, 1596 },
1597 { 1597 {
1598 "defaultMessage": "!!!Hosted", 1598 "defaultMessage": "!!!Hosted",
1599 "end": { 1599 "end": {
1600 "column": 3, 1600 "column": 3,
1601 "line": 49 1601 "line": 50
1602 }, 1602 },
1603 "file": "src/components/settings/services/EditServiceForm.js", 1603 "file": "src/components/settings/services/EditServiceForm.js",
1604 "id": "settings.service.form.tabHosted", 1604 "id": "settings.service.form.tabHosted",
1605 "start": { 1605 "start": {
1606 "column": 13, 1606 "column": 13,
1607 "line": 46 1607 "line": 47
1608 } 1608 }
1609 }, 1609 },
1610 { 1610 {
1611 "defaultMessage": "!!!Self hosted ⭐️", 1611 "defaultMessage": "!!!Self hosted ⭐️",
1612 "end": { 1612 "end": {
1613 "column": 3, 1613 "column": 3,
1614 "line": 53 1614 "line": 54
1615 }, 1615 },
1616 "file": "src/components/settings/services/EditServiceForm.js", 1616 "file": "src/components/settings/services/EditServiceForm.js",
1617 "id": "settings.service.form.tabOnPremise", 1617 "id": "settings.service.form.tabOnPremise",
1618 "start": { 1618 "start": {
1619 "column": 16, 1619 "column": 16,
1620 "line": 50 1620 "line": 51
1621 } 1621 }
1622 }, 1622 },
1623 { 1623 {
1624 "defaultMessage": "!!!Use the hosted {name} service.", 1624 "defaultMessage": "!!!Use the hosted {name} service.",
1625 "end": { 1625 "end": {
1626 "column": 3, 1626 "column": 3,
1627 "line": 57 1627 "line": 58
1628 }, 1628 },
1629 "file": "src/components/settings/services/EditServiceForm.js", 1629 "file": "src/components/settings/services/EditServiceForm.js",
1630 "id": "settings.service.form.useHostedService", 1630 "id": "settings.service.form.useHostedService",
1631 "start": { 1631 "start": {
1632 "column": 20, 1632 "column": 20,
1633 "line": 54 1633 "line": 55
1634 } 1634 }
1635 }, 1635 },
1636 { 1636 {
1637 "defaultMessage": "!!!Could not validate custom {name} server.", 1637 "defaultMessage": "!!!Could not validate custom {name} server.",
1638 "end": { 1638 "end": {
1639 "column": 3, 1639 "column": 3,
1640 "line": 61 1640 "line": 62
1641 }, 1641 },
1642 "file": "src/components/settings/services/EditServiceForm.js", 1642 "file": "src/components/settings/services/EditServiceForm.js",
1643 "id": "settings.service.form.customUrlValidationError", 1643 "id": "settings.service.form.customUrlValidationError",
1644 "start": { 1644 "start": {
1645 "column": 28, 1645 "column": 28,
1646 "line": 58 1646 "line": 59
1647 } 1647 }
1648 }, 1648 },
1649 { 1649 {
1650 "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", 1650 "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.",
1651 "end": { 1651 "end": {
1652 "column": 3, 1652 "column": 3,
1653 "line": 65 1653 "line": 66
1654 }, 1654 },
1655 "file": "src/components/settings/services/EditServiceForm.js", 1655 "file": "src/components/settings/services/EditServiceForm.js",
1656 "id": "settings.service.form.customUrlPremiumInfo", 1656 "id": "settings.service.form.customUrlPremiumInfo",
1657 "start": { 1657 "start": {
1658 "column": 24, 1658 "column": 24,
1659 "line": 62 1659 "line": 63
1660 } 1660 }
1661 }, 1661 },
1662 { 1662 {
1663 "defaultMessage": "!!!Upgrade your account", 1663 "defaultMessage": "!!!Upgrade your account",
1664 "end": { 1664 "end": {
1665 "column": 3, 1665 "column": 3,
1666 "line": 69 1666 "line": 70
1667 }, 1667 },
1668 "file": "src/components/settings/services/EditServiceForm.js", 1668 "file": "src/components/settings/services/EditServiceForm.js",
1669 "id": "settings.service.form.customUrlUpgradeAccount", 1669 "id": "settings.service.form.customUrlUpgradeAccount",
1670 "start": { 1670 "start": {
1671 "column": 27, 1671 "column": 27,
1672 "line": 66 1672 "line": 67
1673 } 1673 }
1674 }, 1674 },
1675 { 1675 {
1676 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", 1676 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
1677 "end": { 1677 "end": {
1678 "column": 3, 1678 "column": 3,
1679 "line": 73 1679 "line": 74
1680 }, 1680 },
1681 "file": "src/components/settings/services/EditServiceForm.js", 1681 "file": "src/components/settings/services/EditServiceForm.js",
1682 "id": "settings.service.form.indirectMessageInfo", 1682 "id": "settings.service.form.indirectMessageInfo",
1683 "start": { 1683 "start": {
1684 "column": 23, 1684 "column": 23,
1685 "line": 70 1685 "line": 71
1686 } 1686 }
1687 }, 1687 },
1688 { 1688 {
1689 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", 1689 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
1690 "end": { 1690 "end": {
1691 "column": 3, 1691 "column": 3,
1692 "line": 77 1692 "line": 78
1693 }, 1693 },
1694 "file": "src/components/settings/services/EditServiceForm.js", 1694 "file": "src/components/settings/services/EditServiceForm.js",
1695 "id": "settings.service.form.isMutedInfo", 1695 "id": "settings.service.form.isMutedInfo",
1696 "start": { 1696 "start": {
1697 "column": 15, 1697 "column": 15,
1698 "line": 74 1698 "line": 75
1699 } 1699 }
1700 }, 1700 },
1701 { 1701 {
1702 "defaultMessage": "!!!Notifications", 1702 "defaultMessage": "!!!Notifications",
1703 "end": { 1703 "end": {
1704 "column": 3, 1704 "column": 3,
1705 "line": 81 1705 "line": 82
1706 }, 1706 },
1707 "file": "src/components/settings/services/EditServiceForm.js", 1707 "file": "src/components/settings/services/EditServiceForm.js",
1708 "id": "settings.service.form.headlineNotifications", 1708 "id": "settings.service.form.headlineNotifications",
1709 "start": { 1709 "start": {
1710 "column": 25, 1710 "column": 25,
1711 "line": 78 1711 "line": 79
1712 } 1712 }
1713 }, 1713 },
1714 { 1714 {
1715 "defaultMessage": "!!!Unread message badges", 1715 "defaultMessage": "!!!Unread message badges",
1716 "end": { 1716 "end": {
1717 "column": 3, 1717 "column": 3,
1718 "line": 85 1718 "line": 86
1719 }, 1719 },
1720 "file": "src/components/settings/services/EditServiceForm.js", 1720 "file": "src/components/settings/services/EditServiceForm.js",
1721 "id": "settings.service.form.headlineBadges", 1721 "id": "settings.service.form.headlineBadges",
1722 "start": { 1722 "start": {
1723 "column": 18, 1723 "column": 18,
1724 "line": 82 1724 "line": 83
1725 } 1725 }
1726 }, 1726 },
1727 { 1727 {
1728 "defaultMessage": "!!!General", 1728 "defaultMessage": "!!!General",
1729 "end": { 1729 "end": {
1730 "column": 3, 1730 "column": 3,
1731 "line": 89 1731 "line": 90
1732 }, 1732 },
1733 "file": "src/components/settings/services/EditServiceForm.js", 1733 "file": "src/components/settings/services/EditServiceForm.js",
1734 "id": "settings.service.form.headlineGeneral", 1734 "id": "settings.service.form.headlineGeneral",
1735 "start": { 1735 "start": {
1736 "column": 19, 1736 "column": 19,
1737 "line": 86 1737 "line": 87
1738 } 1738 }
1739 }, 1739 },
1740 { 1740 {
1741 "defaultMessage": "!!!Delete", 1741 "defaultMessage": "!!!Delete",
1742 "end": { 1742 "end": {
1743 "column": 3, 1743 "column": 3,
1744 "line": 93 1744 "line": 94
1745 }, 1745 },
1746 "file": "src/components/settings/services/EditServiceForm.js", 1746 "file": "src/components/settings/services/EditServiceForm.js",
1747 "id": "settings.service.form.iconDelete", 1747 "id": "settings.service.form.iconDelete",
1748 "start": { 1748 "start": {
1749 "column": 14, 1749 "column": 14,
1750 "line": 90 1750 "line": 91
1751 } 1751 }
1752 }, 1752 },
1753 { 1753 {
1754 "defaultMessage": "!!!Drop your image, or click here", 1754 "defaultMessage": "!!!Drop your image, or click here",
1755 "end": { 1755 "end": {
1756 "column": 3, 1756 "column": 3,
1757 "line": 97 1757 "line": 98
1758 }, 1758 },
1759 "file": "src/components/settings/services/EditServiceForm.js", 1759 "file": "src/components/settings/services/EditServiceForm.js",
1760 "id": "settings.service.form.iconUpload", 1760 "id": "settings.service.form.iconUpload",
1761 "start": { 1761 "start": {
1762 "column": 14, 1762 "column": 14,
1763 "line": 94 1763 "line": 95
1764 } 1764 }
1765 }, 1765 },
1766 { 1766 {
1767 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", 1767 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
1768 "end": { 1768 "end": {
1769 "column": 3, 1769 "column": 3,
1770 "line": 101 1770 "line": 102
1771 }, 1771 },
1772 "file": "src/components/settings/services/EditServiceForm.js", 1772 "file": "src/components/settings/services/EditServiceForm.js",
1773 "id": "settings.service.form.proxy.headline", 1773 "id": "settings.service.form.proxy.headline",
1774 "start": { 1774 "start": {
1775 "column": 17, 1775 "column": 17,
1776 "line": 98 1776 "line": 99
1777 } 1777 }
1778 }, 1778 },
1779 { 1779 {
1780 "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", 1780 "defaultMessage": "!!!Please restart Franz after changing proxy Settings.",
1781 "end": { 1781 "end": {
1782 "column": 3, 1782 "column": 3,
1783 "line": 105 1783 "line": 106
1784 }, 1784 },
1785 "file": "src/components/settings/services/EditServiceForm.js", 1785 "file": "src/components/settings/services/EditServiceForm.js",
1786 "id": "settings.service.form.proxy.restartInfo", 1786 "id": "settings.service.form.proxy.restartInfo",
1787 "start": { 1787 "start": {
1788 "column": 20, 1788 "column": 20,
1789 "line": 102 1789 "line": 103
1790 } 1790 }
1791 }, 1791 },
1792 { 1792 {
1793 "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", 1793 "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.",
1794 "end": { 1794 "end": {
1795 "column": 3, 1795 "column": 3,
1796 "line": 109 1796 "line": 110
1797 }, 1797 },
1798 "file": "src/components/settings/services/EditServiceForm.js", 1798 "file": "src/components/settings/services/EditServiceForm.js",
1799 "id": "settings.service.form.proxy.info", 1799 "id": "settings.service.form.proxy.info",
1800 "start": { 1800 "start": {
1801 "column": 13, 1801 "column": 13,
1802 "line": 106 1802 "line": 107
1803 } 1803 }
1804 } 1804 }
1805 ], 1805 ],
@@ -1912,117 +1912,117 @@
1912 "defaultMessage": "!!!Your services", 1912 "defaultMessage": "!!!Your services",
1913 "end": { 1913 "end": {
1914 "column": 3, 1914 "column": 3,
1915 "line": 17 1915 "line": 18
1916 }, 1916 },
1917 "file": "src/components/settings/services/ServicesDashboard.js", 1917 "file": "src/components/settings/services/ServicesDashboard.js",
1918 "id": "settings.services.headline", 1918 "id": "settings.services.headline",
1919 "start": { 1919 "start": {
1920 "column": 12, 1920 "column": 12,
1921 "line": 14 1921 "line": 15
1922 } 1922 }
1923 }, 1923 },
1924 { 1924 {
1925 "defaultMessage": "!!!Search service", 1925 "defaultMessage": "!!!Search service",
1926 "end": { 1926 "end": {
1927 "column": 3, 1927 "column": 3,
1928 "line": 21 1928 "line": 22
1929 }, 1929 },
1930 "file": "src/components/settings/services/ServicesDashboard.js", 1930 "file": "src/components/settings/services/ServicesDashboard.js",
1931 "id": "settings.searchService", 1931 "id": "settings.searchService",
1932 "start": { 1932 "start": {
1933 "column": 17, 1933 "column": 17,
1934 "line": 18 1934 "line": 19
1935 } 1935 }
1936 }, 1936 },
1937 { 1937 {
1938 "defaultMessage": "!!!You haven't added any services yet.", 1938 "defaultMessage": "!!!You haven't added any services yet.",
1939 "end": { 1939 "end": {
1940 "column": 3, 1940 "column": 3,
1941 "line": 25 1941 "line": 26
1942 }, 1942 },
1943 "file": "src/components/settings/services/ServicesDashboard.js", 1943 "file": "src/components/settings/services/ServicesDashboard.js",
1944 "id": "settings.services.noServicesAdded", 1944 "id": "settings.services.noServicesAdded",
1945 "start": { 1945 "start": {
1946 "column": 19, 1946 "column": 19,
1947 "line": 22 1947 "line": 23
1948 } 1948 }
1949 }, 1949 },
1950 { 1950 {
1951 "defaultMessage": "!!!Sorry, but no service matched your search term.", 1951 "defaultMessage": "!!!Sorry, but no service matched your search term.",
1952 "end": { 1952 "end": {
1953 "column": 3, 1953 "column": 3,
1954 "line": 29 1954 "line": 30
1955 }, 1955 },
1956 "file": "src/components/settings/services/ServicesDashboard.js", 1956 "file": "src/components/settings/services/ServicesDashboard.js",
1957 "id": "settings.recipes.nothingFound", 1957 "id": "settings.recipes.nothingFound",
1958 "start": { 1958 "start": {
1959 "column": 18, 1959 "column": 18,
1960 "line": 26 1960 "line": 27
1961 } 1961 }
1962 }, 1962 },
1963 { 1963 {
1964 "defaultMessage": "!!!Discover services", 1964 "defaultMessage": "!!!Discover services",
1965 "end": { 1965 "end": {
1966 "column": 3, 1966 "column": 3,
1967 "line": 33 1967 "line": 34
1968 }, 1968 },
1969 "file": "src/components/settings/services/ServicesDashboard.js", 1969 "file": "src/components/settings/services/ServicesDashboard.js",
1970 "id": "settings.services.discoverServices", 1970 "id": "settings.services.discoverServices",
1971 "start": { 1971 "start": {
1972 "column": 20, 1972 "column": 20,
1973 "line": 30 1973 "line": 31
1974 } 1974 }
1975 }, 1975 },
1976 { 1976 {
1977 "defaultMessage": "!!!Could not load your services", 1977 "defaultMessage": "!!!Could not load your services",
1978 "end": { 1978 "end": {
1979 "column": 3, 1979 "column": 3,
1980 "line": 37 1980 "line": 38
1981 }, 1981 },
1982 "file": "src/components/settings/services/ServicesDashboard.js", 1982 "file": "src/components/settings/services/ServicesDashboard.js",
1983 "id": "settings.services.servicesRequestFailed", 1983 "id": "settings.services.servicesRequestFailed",
1984 "start": { 1984 "start": {
1985 "column": 25, 1985 "column": 25,
1986 "line": 34 1986 "line": 35
1987 } 1987 }
1988 }, 1988 },
1989 { 1989 {
1990 "defaultMessage": "!!!Try again", 1990 "defaultMessage": "!!!Try again",
1991 "end": { 1991 "end": {
1992 "column": 3, 1992 "column": 3,
1993 "line": 41 1993 "line": 42
1994 }, 1994 },
1995 "file": "src/components/settings/services/ServicesDashboard.js", 1995 "file": "src/components/settings/services/ServicesDashboard.js",
1996 "id": "settings.account.tryReloadServices", 1996 "id": "settings.account.tryReloadServices",
1997 "start": { 1997 "start": {
1998 "column": 21, 1998 "column": 21,
1999 "line": 38 1999 "line": 39
2000 } 2000 }
2001 }, 2001 },
2002 { 2002 {
2003 "defaultMessage": "!!!Your changes have been saved", 2003 "defaultMessage": "!!!Your changes have been saved",
2004 "end": { 2004 "end": {
2005 "column": 3, 2005 "column": 3,
2006 "line": 45 2006 "line": 46
2007 }, 2007 },
2008 "file": "src/components/settings/services/ServicesDashboard.js", 2008 "file": "src/components/settings/services/ServicesDashboard.js",
2009 "id": "settings.services.updatedInfo", 2009 "id": "settings.services.updatedInfo",
2010 "start": { 2010 "start": {
2011 "column": 15, 2011 "column": 15,
2012 "line": 42 2012 "line": 43
2013 } 2013 }
2014 }, 2014 },
2015 { 2015 {
2016 "defaultMessage": "!!!Service has been deleted", 2016 "defaultMessage": "!!!Service has been deleted",
2017 "end": { 2017 "end": {
2018 "column": 3, 2018 "column": 3,
2019 "line": 49 2019 "line": 50
2020 }, 2020 },
2021 "file": "src/components/settings/services/ServicesDashboard.js", 2021 "file": "src/components/settings/services/ServicesDashboard.js",
2022 "id": "settings.services.deletedInfo", 2022 "id": "settings.services.deletedInfo",
2023 "start": { 2023 "start": {
2024 "column": 15, 2024 "column": 15,
2025 "line": 46 2025 "line": 47
2026 } 2026 }
2027 } 2027 }
2028 ], 2028 ],
@@ -3266,6 +3266,55 @@
3266 { 3266 {
3267 "descriptors": [ 3267 "descriptors": [
3268 { 3268 {
3269 "defaultMessage": "!!!Changes in Franz {version}",
3270 "end": {
3271 "column": 3,
3272 "line": 23
3273 },
3274 "file": "src/features/serviceLimit/components/AnnouncementScreen.js",
3275 "id": "feature.announcements.changelog.headline",
3276 "start": {
3277 "column": 12,
3278 "line": 20
3279 }
3280 }
3281 ],
3282 "path": "src/features/serviceLimit/components/AnnouncementScreen.json"
3283 },
3284 {
3285 "descriptors": [
3286 {
3287 "defaultMessage": "!!!You have added {amount} of {amount} services. Please upgrade your account to add more services.",
3288 "end": {
3289 "column": 3,
3290 "line": 16
3291 },
3292 "file": "src/features/serviceLimit/components/LimitReachedInfobox.js",
3293 "id": "feature.serviceLimit.limitReached",
3294 "start": {
3295 "column": 16,
3296 "line": 13
3297 }
3298 },
3299 {
3300 "defaultMessage": "!!!Upgrade account",
3301 "end": {
3302 "column": 3,
3303 "line": 20
3304 },
3305 "file": "src/features/serviceLimit/components/LimitReachedInfobox.js",
3306 "id": "premiumFeature.button.upgradeAccount",
3307 "start": {
3308 "column": 10,
3309 "line": 17
3310 }
3311 }
3312 ],
3313 "path": "src/features/serviceLimit/components/LimitReachedInfobox.json"
3314 },
3315 {
3316 "descriptors": [
3317 {
3269 "defaultMessage": "!!!Franz is better together!", 3318 "defaultMessage": "!!!Franz is better together!",
3270 "end": { 3319 "end": {
3271 "column": 3, 3320 "column": 3,
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 @@
5 "feature.delayApp.action": "Get a Franz Supporter License", 5 "feature.delayApp.action": "Get a Franz Supporter License",
6 "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting", 6 "feature.delayApp.headline": "Please purchase a Franz Supporter License to skip waiting",
7 "feature.delayApp.text": "Franz will continue in {seconds} seconds.", 7 "feature.delayApp.text": "Franz will continue in {seconds} seconds.",
8 "feature.serviceLimit.limitReached": "You have added {amount} of {limit} services. Please upgrade your account to add more services.",
8 "feature.shareFranz.action.email": "Send as email", 9 "feature.shareFranz.action.email": "Send as email",
9 "feature.shareFranz.action.facebook": "Share on Facebook", 10 "feature.shareFranz.action.facebook": "Share on Facebook",
10 "feature.shareFranz.action.twitter": "Share on Twitter", 11 "feature.shareFranz.action.twitter": "Share on Twitter",
@@ -328,4 +329,4 @@
328 "workspaceDrawer.workspaceFeatureInfo": "<p>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.</p><p>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.</p>", 329 "workspaceDrawer.workspaceFeatureInfo": "<p>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.</p><p>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.</p>",
329 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings", 330 "workspaceDrawer.workspacesSettingsTooltip": "Edit workspaces settings",
330 "workspaces.switchingIndicator.switchingTo": "Switching to" 331 "workspaces.switchingIndicator.switchingTo": "Switching to"
331} \ No newline at end of file 332}
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 @@
4 "defaultMessage": "!!!Available Services", 4 "defaultMessage": "!!!Available Services",
5 "file": "src/components/settings/recipes/RecipesDashboard.js", 5 "file": "src/components/settings/recipes/RecipesDashboard.js",
6 "start": { 6 "start": {
7 "line": 15, 7 "line": 16,
8 "column": 12 8 "column": 12
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 18, 11 "line": 19,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Search service", 17 "defaultMessage": "!!!Search service",
18 "file": "src/components/settings/recipes/RecipesDashboard.js", 18 "file": "src/components/settings/recipes/RecipesDashboard.js",
19 "start": { 19 "start": {
20 "line": 19, 20 "line": 20,
21 "column": 17 21 "column": 17
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 22, 24 "line": 23,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Most popular", 30 "defaultMessage": "!!!Most popular",
31 "file": "src/components/settings/recipes/RecipesDashboard.js", 31 "file": "src/components/settings/recipes/RecipesDashboard.js",
32 "start": { 32 "start": {
33 "line": 23, 33 "line": 24,
34 "column": 22 34 "column": 22
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 26, 37 "line": 27,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,11 @@
43 "defaultMessage": "!!!All services", 43 "defaultMessage": "!!!All services",
44 "file": "src/components/settings/recipes/RecipesDashboard.js", 44 "file": "src/components/settings/recipes/RecipesDashboard.js",
45 "start": { 45 "start": {
46 "line": 27, 46 "line": 28,
47 "column": 14 47 "column": 14
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 30, 50 "line": 31,
51 "column": 3 51 "column": 3
52 } 52 }
53 }, 53 },
@@ -56,11 +56,11 @@
56 "defaultMessage": "!!!Development", 56 "defaultMessage": "!!!Development",
57 "file": "src/components/settings/recipes/RecipesDashboard.js", 57 "file": "src/components/settings/recipes/RecipesDashboard.js",
58 "start": { 58 "start": {
59 "line": 31, 59 "line": 32,
60 "column": 14 60 "column": 14
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 34, 63 "line": 35,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
69 "defaultMessage": "!!!Sorry, but no service matched your search term.", 69 "defaultMessage": "!!!Sorry, but no service matched your search term.",
70 "file": "src/components/settings/recipes/RecipesDashboard.js", 70 "file": "src/components/settings/recipes/RecipesDashboard.js",
71 "start": { 71 "start": {
72 "line": 35, 72 "line": 36,
73 "column": 16 73 "column": 16
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 38, 76 "line": 39,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Service successfully added", 82 "defaultMessage": "!!!Service successfully added",
83 "file": "src/components/settings/recipes/RecipesDashboard.js", 83 "file": "src/components/settings/recipes/RecipesDashboard.js",
84 "start": { 84 "start": {
85 "line": 39, 85 "line": 40,
86 "column": 31 86 "column": 31
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 42, 89 "line": 43,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Missing a service?", 95 "defaultMessage": "!!!Missing a service?",
96 "file": "src/components/settings/recipes/RecipesDashboard.js", 96 "file": "src/components/settings/recipes/RecipesDashboard.js",
97 "start": { 97 "start": {
98 "line": 43, 98 "line": 44,
99 "column": 18 99 "column": 18
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 46, 102 "line": 47,
103 "column": 3 103 "column": 3
104 } 104 }
105 } 105 }
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 @@
4 "defaultMessage": "!!!Save service", 4 "defaultMessage": "!!!Save service",
5 "file": "src/components/settings/services/EditServiceForm.js", 5 "file": "src/components/settings/services/EditServiceForm.js",
6 "start": { 6 "start": {
7 "line": 22, 7 "line": 24,
8 "column": 15 8 "column": 15
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 25, 11 "line": 27,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Delete Service", 17 "defaultMessage": "!!!Delete Service",
18 "file": "src/components/settings/services/EditServiceForm.js", 18 "file": "src/components/settings/services/EditServiceForm.js",
19 "start": { 19 "start": {
20 "line": 26, 20 "line": 28,
21 "column": 17 21 "column": 17
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 29, 24 "line": 31,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Available services", 30 "defaultMessage": "!!!Available services",
31 "file": "src/components/settings/services/EditServiceForm.js", 31 "file": "src/components/settings/services/EditServiceForm.js",
32 "start": { 32 "start": {
33 "line": 30, 33 "line": 32,
34 "column": 21 34 "column": 21
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 33, 37 "line": 35,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,11 @@
43 "defaultMessage": "!!!Your services", 43 "defaultMessage": "!!!Your services",
44 "file": "src/components/settings/services/EditServiceForm.js", 44 "file": "src/components/settings/services/EditServiceForm.js",
45 "start": { 45 "start": {
46 "line": 34, 46 "line": 36,
47 "column": 16 47 "column": 16
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 37, 50 "line": 39,
51 "column": 3 51 "column": 3
52 } 52 }
53 }, 53 },
@@ -56,11 +56,11 @@
56 "defaultMessage": "!!!Add {name}", 56 "defaultMessage": "!!!Add {name}",
57 "file": "src/components/settings/services/EditServiceForm.js", 57 "file": "src/components/settings/services/EditServiceForm.js",
58 "start": { 58 "start": {
59 "line": 38, 59 "line": 40,
60 "column": 22 60 "column": 22
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 41, 63 "line": 43,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
69 "defaultMessage": "!!!Edit {name}", 69 "defaultMessage": "!!!Edit {name}",
70 "file": "src/components/settings/services/EditServiceForm.js", 70 "file": "src/components/settings/services/EditServiceForm.js",
71 "start": { 71 "start": {
72 "line": 42, 72 "line": 44,
73 "column": 23 73 "column": 23
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 45, 76 "line": 47,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Hosted", 82 "defaultMessage": "!!!Hosted",
83 "file": "src/components/settings/services/EditServiceForm.js", 83 "file": "src/components/settings/services/EditServiceForm.js",
84 "start": { 84 "start": {
85 "line": 46, 85 "line": 48,
86 "column": 13 86 "column": 13
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 49, 89 "line": 51,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Self hosted ⭐️", 95 "defaultMessage": "!!!Self hosted ⭐️",
96 "file": "src/components/settings/services/EditServiceForm.js", 96 "file": "src/components/settings/services/EditServiceForm.js",
97 "start": { 97 "start": {
98 "line": 50, 98 "line": 52,
99 "column": 16 99 "column": 16
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 53, 102 "line": 55,
103 "column": 3 103 "column": 3
104 } 104 }
105 }, 105 },
@@ -108,11 +108,11 @@
108 "defaultMessage": "!!!Use the hosted {name} service.", 108 "defaultMessage": "!!!Use the hosted {name} service.",
109 "file": "src/components/settings/services/EditServiceForm.js", 109 "file": "src/components/settings/services/EditServiceForm.js",
110 "start": { 110 "start": {
111 "line": 54, 111 "line": 56,
112 "column": 20 112 "column": 20
113 }, 113 },
114 "end": { 114 "end": {
115 "line": 57, 115 "line": 59,
116 "column": 3 116 "column": 3
117 } 117 }
118 }, 118 },
@@ -121,11 +121,11 @@
121 "defaultMessage": "!!!Could not validate custom {name} server.", 121 "defaultMessage": "!!!Could not validate custom {name} server.",
122 "file": "src/components/settings/services/EditServiceForm.js", 122 "file": "src/components/settings/services/EditServiceForm.js",
123 "start": { 123 "start": {
124 "line": 58, 124 "line": 60,
125 "column": 28 125 "column": 28
126 }, 126 },
127 "end": { 127 "end": {
128 "line": 61, 128 "line": 63,
129 "column": 3 129 "column": 3
130 } 130 }
131 }, 131 },
@@ -134,11 +134,11 @@
134 "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.", 134 "defaultMessage": "!!!To add self hosted services, you need a Franz Premium Supporter Account.",
135 "file": "src/components/settings/services/EditServiceForm.js", 135 "file": "src/components/settings/services/EditServiceForm.js",
136 "start": { 136 "start": {
137 "line": 62, 137 "line": 64,
138 "column": 24 138 "column": 24
139 }, 139 },
140 "end": { 140 "end": {
141 "line": 65, 141 "line": 67,
142 "column": 3 142 "column": 3
143 } 143 }
144 }, 144 },
@@ -147,11 +147,11 @@
147 "defaultMessage": "!!!Upgrade your account", 147 "defaultMessage": "!!!Upgrade your account",
148 "file": "src/components/settings/services/EditServiceForm.js", 148 "file": "src/components/settings/services/EditServiceForm.js",
149 "start": { 149 "start": {
150 "line": 66, 150 "line": 68,
151 "column": 27 151 "column": 27
152 }, 152 },
153 "end": { 153 "end": {
154 "line": 69, 154 "line": 71,
155 "column": 3 155 "column": 3
156 } 156 }
157 }, 157 },
@@ -160,11 +160,11 @@
160 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...", 160 "defaultMessage": "!!!You will be notified about all new messages in a channel, not just @username, @channel, @here, ...",
161 "file": "src/components/settings/services/EditServiceForm.js", 161 "file": "src/components/settings/services/EditServiceForm.js",
162 "start": { 162 "start": {
163 "line": 70, 163 "line": 72,
164 "column": 23 164 "column": 23
165 }, 165 },
166 "end": { 166 "end": {
167 "line": 73, 167 "line": 75,
168 "column": 3 168 "column": 3
169 } 169 }
170 }, 170 },
@@ -173,11 +173,11 @@
173 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted", 173 "defaultMessage": "!!!When disabled, all notification sounds and audio playback are muted",
174 "file": "src/components/settings/services/EditServiceForm.js", 174 "file": "src/components/settings/services/EditServiceForm.js",
175 "start": { 175 "start": {
176 "line": 74, 176 "line": 76,
177 "column": 15 177 "column": 15
178 }, 178 },
179 "end": { 179 "end": {
180 "line": 77, 180 "line": 79,
181 "column": 3 181 "column": 3
182 } 182 }
183 }, 183 },
@@ -186,11 +186,11 @@
186 "defaultMessage": "!!!Notifications", 186 "defaultMessage": "!!!Notifications",
187 "file": "src/components/settings/services/EditServiceForm.js", 187 "file": "src/components/settings/services/EditServiceForm.js",
188 "start": { 188 "start": {
189 "line": 78, 189 "line": 80,
190 "column": 25 190 "column": 25
191 }, 191 },
192 "end": { 192 "end": {
193 "line": 81, 193 "line": 83,
194 "column": 3 194 "column": 3
195 } 195 }
196 }, 196 },
@@ -199,11 +199,11 @@
199 "defaultMessage": "!!!Unread message badges", 199 "defaultMessage": "!!!Unread message badges",
200 "file": "src/components/settings/services/EditServiceForm.js", 200 "file": "src/components/settings/services/EditServiceForm.js",
201 "start": { 201 "start": {
202 "line": 82, 202 "line": 84,
203 "column": 18 203 "column": 18
204 }, 204 },
205 "end": { 205 "end": {
206 "line": 85, 206 "line": 87,
207 "column": 3 207 "column": 3
208 } 208 }
209 }, 209 },
@@ -212,11 +212,11 @@
212 "defaultMessage": "!!!General", 212 "defaultMessage": "!!!General",
213 "file": "src/components/settings/services/EditServiceForm.js", 213 "file": "src/components/settings/services/EditServiceForm.js",
214 "start": { 214 "start": {
215 "line": 86, 215 "line": 88,
216 "column": 19 216 "column": 19
217 }, 217 },
218 "end": { 218 "end": {
219 "line": 89, 219 "line": 91,
220 "column": 3 220 "column": 3
221 } 221 }
222 }, 222 },
@@ -225,11 +225,11 @@
225 "defaultMessage": "!!!Delete", 225 "defaultMessage": "!!!Delete",
226 "file": "src/components/settings/services/EditServiceForm.js", 226 "file": "src/components/settings/services/EditServiceForm.js",
227 "start": { 227 "start": {
228 "line": 90, 228 "line": 92,
229 "column": 14 229 "column": 14
230 }, 230 },
231 "end": { 231 "end": {
232 "line": 93, 232 "line": 95,
233 "column": 3 233 "column": 3
234 } 234 }
235 }, 235 },
@@ -238,11 +238,11 @@
238 "defaultMessage": "!!!Drop your image, or click here", 238 "defaultMessage": "!!!Drop your image, or click here",
239 "file": "src/components/settings/services/EditServiceForm.js", 239 "file": "src/components/settings/services/EditServiceForm.js",
240 "start": { 240 "start": {
241 "line": 94, 241 "line": 96,
242 "column": 14 242 "column": 14
243 }, 243 },
244 "end": { 244 "end": {
245 "line": 97, 245 "line": 99,
246 "column": 3 246 "column": 3
247 } 247 }
248 }, 248 },
@@ -251,11 +251,11 @@
251 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings", 251 "defaultMessage": "!!!HTTP/HTTPS Proxy Settings",
252 "file": "src/components/settings/services/EditServiceForm.js", 252 "file": "src/components/settings/services/EditServiceForm.js",
253 "start": { 253 "start": {
254 "line": 98, 254 "line": 100,
255 "column": 17 255 "column": 17
256 }, 256 },
257 "end": { 257 "end": {
258 "line": 101, 258 "line": 103,
259 "column": 3 259 "column": 3
260 } 260 }
261 }, 261 },
@@ -264,11 +264,11 @@
264 "defaultMessage": "!!!Please restart Franz after changing proxy Settings.", 264 "defaultMessage": "!!!Please restart Franz after changing proxy Settings.",
265 "file": "src/components/settings/services/EditServiceForm.js", 265 "file": "src/components/settings/services/EditServiceForm.js",
266 "start": { 266 "start": {
267 "line": 102, 267 "line": 104,
268 "column": 20 268 "column": 20
269 }, 269 },
270 "end": { 270 "end": {
271 "line": 105, 271 "line": 107,
272 "column": 3 272 "column": 3
273 } 273 }
274 }, 274 },
@@ -277,11 +277,11 @@
277 "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.", 277 "defaultMessage": "!!!Proxy settings will not be synchronized with the Franz servers.",
278 "file": "src/components/settings/services/EditServiceForm.js", 278 "file": "src/components/settings/services/EditServiceForm.js",
279 "start": { 279 "start": {
280 "line": 106, 280 "line": 108,
281 "column": 13 281 "column": 13
282 }, 282 },
283 "end": { 283 "end": {
284 "line": 109, 284 "line": 111,
285 "column": 3 285 "column": 3
286 } 286 }
287 } 287 }
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 @@
4 "defaultMessage": "!!!Your services", 4 "defaultMessage": "!!!Your services",
5 "file": "src/components/settings/services/ServicesDashboard.js", 5 "file": "src/components/settings/services/ServicesDashboard.js",
6 "start": { 6 "start": {
7 "line": 14, 7 "line": 15,
8 "column": 12 8 "column": 12
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 17, 11 "line": 18,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!Search service", 17 "defaultMessage": "!!!Search service",
18 "file": "src/components/settings/services/ServicesDashboard.js", 18 "file": "src/components/settings/services/ServicesDashboard.js",
19 "start": { 19 "start": {
20 "line": 18, 20 "line": 19,
21 "column": 17 21 "column": 17
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 21, 24 "line": 22,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!You haven't added any services yet.", 30 "defaultMessage": "!!!You haven't added any services yet.",
31 "file": "src/components/settings/services/ServicesDashboard.js", 31 "file": "src/components/settings/services/ServicesDashboard.js",
32 "start": { 32 "start": {
33 "line": 22, 33 "line": 23,
34 "column": 19 34 "column": 19
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 25, 37 "line": 26,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,11 @@
43 "defaultMessage": "!!!Sorry, but no service matched your search term.", 43 "defaultMessage": "!!!Sorry, but no service matched your search term.",
44 "file": "src/components/settings/services/ServicesDashboard.js", 44 "file": "src/components/settings/services/ServicesDashboard.js",
45 "start": { 45 "start": {
46 "line": 26, 46 "line": 27,
47 "column": 18 47 "column": 18
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 29, 50 "line": 30,
51 "column": 3 51 "column": 3
52 } 52 }
53 }, 53 },
@@ -56,11 +56,11 @@
56 "defaultMessage": "!!!Discover services", 56 "defaultMessage": "!!!Discover services",
57 "file": "src/components/settings/services/ServicesDashboard.js", 57 "file": "src/components/settings/services/ServicesDashboard.js",
58 "start": { 58 "start": {
59 "line": 30, 59 "line": 31,
60 "column": 20 60 "column": 20
61 }, 61 },
62 "end": { 62 "end": {
63 "line": 33, 63 "line": 34,
64 "column": 3 64 "column": 3
65 } 65 }
66 }, 66 },
@@ -69,11 +69,11 @@
69 "defaultMessage": "!!!Could not load your services", 69 "defaultMessage": "!!!Could not load your services",
70 "file": "src/components/settings/services/ServicesDashboard.js", 70 "file": "src/components/settings/services/ServicesDashboard.js",
71 "start": { 71 "start": {
72 "line": 34, 72 "line": 35,
73 "column": 25 73 "column": 25
74 }, 74 },
75 "end": { 75 "end": {
76 "line": 37, 76 "line": 38,
77 "column": 3 77 "column": 3
78 } 78 }
79 }, 79 },
@@ -82,11 +82,11 @@
82 "defaultMessage": "!!!Try again", 82 "defaultMessage": "!!!Try again",
83 "file": "src/components/settings/services/ServicesDashboard.js", 83 "file": "src/components/settings/services/ServicesDashboard.js",
84 "start": { 84 "start": {
85 "line": 38, 85 "line": 39,
86 "column": 21 86 "column": 21
87 }, 87 },
88 "end": { 88 "end": {
89 "line": 41, 89 "line": 42,
90 "column": 3 90 "column": 3
91 } 91 }
92 }, 92 },
@@ -95,11 +95,11 @@
95 "defaultMessage": "!!!Your changes have been saved", 95 "defaultMessage": "!!!Your changes have been saved",
96 "file": "src/components/settings/services/ServicesDashboard.js", 96 "file": "src/components/settings/services/ServicesDashboard.js",
97 "start": { 97 "start": {
98 "line": 42, 98 "line": 43,
99 "column": 15 99 "column": 15
100 }, 100 },
101 "end": { 101 "end": {
102 "line": 45, 102 "line": 46,
103 "column": 3 103 "column": 3
104 } 104 }
105 }, 105 },
@@ -108,11 +108,11 @@
108 "defaultMessage": "!!!Service has been deleted", 108 "defaultMessage": "!!!Service has been deleted",
109 "file": "src/components/settings/services/ServicesDashboard.js", 109 "file": "src/components/settings/services/ServicesDashboard.js",
110 "start": { 110 "start": {
111 "line": 46, 111 "line": 47,
112 "column": 15 112 "column": 15
113 }, 113 },
114 "end": { 114 "end": {
115 "line": 49, 115 "line": 50,
116 "column": 3 116 "column": 3
117 } 117 }
118 } 118 }
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 @@
1[
2 {
3 "id": "feature.announcements.changelog.headline",
4 "defaultMessage": "!!!Changes in Franz {version}",
5 "file": "src/features/serviceLimit/components/AnnouncementScreen.js",
6 "start": {
7 "line": 20,
8 "column": 12
9 },
10 "end": {
11 "line": 23,
12 "column": 3
13 }
14 }
15] \ 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 @@
1[
2 {
3 "id": "feature.serviceLimit.limitReached",
4 "defaultMessage": "!!!You have added {amount} of {limit} services. Please upgrade your account to add more services.",
5 "file": "src/features/serviceLimit/components/LimitReachedInfobox.js",
6 "start": {
7 "line": 11,
8 "column": 16
9 },
10 "end": {
11 "line": 14,
12 "column": 3
13 }
14 },
15 {
16 "id": "premiumFeature.button.upgradeAccount",
17 "defaultMessage": "!!!Upgrade account",
18 "file": "src/features/serviceLimit/components/LimitReachedInfobox.js",
19 "start": {
20 "line": 15,
21 "column": 10
22 },
23 "end": {
24 "line": 18,
25 "column": 3
26 }
27 }
28] \ 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';
16import shareFranz from '../features/shareFranz'; 16import shareFranz from '../features/shareFranz';
17import announcements from '../features/announcements'; 17import announcements from '../features/announcements';
18import settingsWS from '../features/settingsWS'; 18import settingsWS from '../features/settingsWS';
19import serviceLimit from '../features/serviceLimit';
19 20
20import { DEFAULT_FEATURES_CONFIG } from '../config'; 21import { DEFAULT_FEATURES_CONFIG } from '../config';
21 22
@@ -75,5 +76,6 @@ export default class FeaturesStore extends Store {
75 shareFranz(this.stores, this.actions); 76 shareFranz(this.stores, this.actions);
76 announcements(this.stores, this.actions); 77 announcements(this.stores, this.actions);
77 settingsWS(this.stores, this.actions); 78 settingsWS(this.stores, this.actions);
79 serviceLimit(this.stores, this.actions);
78 } 80 }
79} 81}
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';
13import { matchRoute } from '../helpers/routing-helpers'; 13import { matchRoute } from '../helpers/routing-helpers';
14import { gaEvent, statsEvent } from '../lib/analytics'; 14import { gaEvent, statsEvent } from '../lib/analytics';
15import { workspaceStore } from '../features/workspaces'; 15import { workspaceStore } from '../features/workspaces';
16import { serviceLimitStore } from '../features/serviceLimit';
16 17
17const debug = require('debug')('Franz:ServiceStore'); 18const debug = require('debug')('Franz:ServiceStore');
18 19
@@ -164,6 +165,8 @@ export default class ServicesStore extends Store {
164 165
165 // Actions 166 // Actions
166 @action async _createService({ recipeId, serviceData, redirect = true }) { 167 @action async _createService({ recipeId, serviceData, redirect = true }) {
168 if (serviceLimitStore.userHasReachedServiceLimit) return;
169
167 const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData); 170 const data = this._cleanUpTeamIdAndCustomUrl(recipeId, serviceData);
168 171
169 const response = await this.createServiceRequest.execute(recipeId, data)._promise; 172 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';
12import GlobalErrorStore from './GlobalErrorStore'; 12import GlobalErrorStore from './GlobalErrorStore';
13import { workspaceStore } from '../features/workspaces'; 13import { workspaceStore } from '../features/workspaces';
14import { announcementsStore } from '../features/announcements'; 14import { announcementsStore } from '../features/announcements';
15import { serviceLimitStore } from '../features/serviceLimit';
15 16
16export default (api, actions, router) => { 17export default (api, actions, router) => {
17 const stores = {}; 18 const stores = {};
@@ -31,6 +32,7 @@ export default (api, actions, router) => {
31 globalError: new GlobalErrorStore(stores, api, actions), 32 globalError: new GlobalErrorStore(stores, api, actions),
32 workspaces: workspaceStore, 33 workspaces: workspaceStore,
33 announcements: announcementsStore, 34 announcements: announcementsStore,
35 serviceLimit: serviceLimitStore,
34 }); 36 });
35 // Initialize all stores 37 // Initialize all stores
36 Object.keys(stores).forEach((name) => { 38 Object.keys(stores).forEach((name) => {