aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/auth/Import.js2
-rw-r--r--src/components/auth/Welcome.js12
-rw-r--r--src/components/layout/AppLayout.js8
-rw-r--r--src/components/layout/Sidebar.js10
-rw-r--r--src/components/services/content/ServiceDisabled.js2
-rw-r--r--src/components/services/content/ServiceWebview.js35
-rw-r--r--src/components/services/content/WebviewCrashHandler.js2
-rw-r--r--src/components/services/tabs/TabBarSortableList.js6
-rw-r--r--src/components/services/tabs/TabItem.js37
-rw-r--r--src/components/services/tabs/Tabbar.js9
-rw-r--r--src/components/settings/account/AccountDashboard.js49
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js1
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js57
-rw-r--r--src/components/settings/services/EditServiceForm.js79
-rw-r--r--src/components/settings/settings/EditSettingsForm.js38
-rw-r--r--src/components/ui/AppLoader.js2
-rw-r--r--src/components/ui/Button.js2
-rw-r--r--src/components/ui/InfoBar.js7
-rw-r--r--src/components/ui/Loader.js5
-rw-r--r--src/components/ui/Subscription.js19
-rw-r--r--src/components/ui/SubscriptionPopup.js1
21 files changed, 284 insertions, 99 deletions
diff --git a/src/components/auth/Import.js b/src/components/auth/Import.js
index 06493a0fd..078244434 100644
--- a/src/components/auth/Import.js
+++ b/src/components/auth/Import.js
@@ -24,7 +24,7 @@ const messages = defineMessages({
24 }, 24 },
25 skipButtonLabel: { 25 skipButtonLabel: {
26 id: 'import.skip.label', 26 id: 'import.skip.label',
27 defaultMessage: '!!!I want add services manually', 27 defaultMessage: '!!!I want to add services manually',
28 }, 28 },
29}); 29});
30 30
diff --git a/src/components/auth/Welcome.js b/src/components/auth/Welcome.js
index 06b10ecfe..eb9fbb847 100644
--- a/src/components/auth/Welcome.js
+++ b/src/components/auth/Welcome.js
@@ -55,12 +55,16 @@ export default class Login extends Component {
55 </div> 55 </div>
56 <div className="welcome__featured-services"> 56 <div className="welcome__featured-services">
57 {recipes.map(recipe => ( 57 {recipes.map(recipe => (
58 <img 58 <div
59 key={recipe.id} 59 key={recipe.id}
60 src={recipe.icons.svg}
61 className="welcome__featured-service" 60 className="welcome__featured-service"
62 alt="" 61 >
63 /> 62 <img
63 key={recipe.id}
64 src={recipe.icons.svg}
65 alt=""
66 />
67 </div>
64 ))} 68 ))}
65 </div> 69 </div>
66 </div> 70 </div>
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index f60c170a8..20dc2f764 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -23,6 +23,10 @@ const messages = defineMessages({
23 id: 'infobar.buttonReloadServices', 23 id: 'infobar.buttonReloadServices',
24 defaultMessage: '!!!Reload services', 24 defaultMessage: '!!!Reload services',
25 }, 25 },
26 changelog: {
27 id: 'infobar.buttonChangelog',
28 defaultMessage: '!!!Changelog',
29 },
26 buttonInstallUpdate: { 30 buttonInstallUpdate: {
27 id: 'infobar.buttonInstallUpdate', 31 id: 'infobar.buttonInstallUpdate',
28 defaultMessage: '!!!Restart & install update', 32 defaultMessage: '!!!Restart & install update',
@@ -135,7 +139,9 @@ export default class AppLayout extends Component {
135 sticky 139 sticky
136 > 140 >
137 <span className="mdi mdi-information" /> 141 <span className="mdi mdi-information" />
138 {intl.formatMessage(messages.updateAvailable)} 142 {intl.formatMessage(messages.updateAvailable)} <a href="https://meetfranz.com/changelog" target="_blank">
143 <u>{intl.formatMessage(messages.changelog)}</u>
144 </a>
139 </InfoBar> 145 </InfoBar>
140 )} 146 )}
141 {services} 147 {services}
diff --git a/src/components/layout/Sidebar.js b/src/components/layout/Sidebar.js
index ea34e8702..915ebeace 100644
--- a/src/components/layout/Sidebar.js
+++ b/src/components/layout/Sidebar.js
@@ -2,6 +2,7 @@ import React, { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import ReactTooltip from 'react-tooltip'; 3import ReactTooltip from 'react-tooltip';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import { observer } from 'mobx-react';
5 6
6import Tabbar from '../services/tabs/Tabbar'; 7import Tabbar from '../services/tabs/Tabbar';
7import { ctrlKey } from '../../environment'; 8import { ctrlKey } from '../../environment';
@@ -16,15 +17,16 @@ const messages = defineMessages({
16 defaultMessage: '!!!Add new service', 17 defaultMessage: '!!!Add new service',
17 }, 18 },
18 mute: { 19 mute: {
19 id: 'sidebar.mute', 20 id: 'sidebar.muteApp',
20 defaultMessage: '!!!Disable audio', 21 defaultMessage: '!!!Disable notifications & audio',
21 }, 22 },
22 unmute: { 23 unmute: {
23 id: 'sidebar.unmute', 24 id: 'sidebar.unmuteApp',
24 defaultMessage: '!!!Enable audio', 25 defaultMessage: '!!!Enable notifications & audio',
25 }, 26 },
26}); 27});
27 28
29@observer
28export default class Sidebar extends Component { 30export default class Sidebar extends Component {
29 static propTypes = { 31 static propTypes = {
30 openSettings: PropTypes.func.isRequired, 32 openSettings: PropTypes.func.isRequired,
diff --git a/src/components/services/content/ServiceDisabled.js b/src/components/services/content/ServiceDisabled.js
index 732b6c003..b5af3743d 100644
--- a/src/components/services/content/ServiceDisabled.js
+++ b/src/components/services/content/ServiceDisabled.js
@@ -35,7 +35,7 @@ export default class ServiceDisabled extends Component {
35 const { intl } = this.context; 35 const { intl } = this.context;
36 36
37 return ( 37 return (
38 <div className="services__crash-handler"> 38 <div className="services__info-layer">
39 <h1>{intl.formatMessage(messages.headline, { name })}</h1> 39 <h1>{intl.formatMessage(messages.headline, { name })}</h1>
40 <Button 40 <Button
41 label={intl.formatMessage(messages.action, { name })} 41 label={intl.formatMessage(messages.action, { name })}
diff --git a/src/components/services/content/ServiceWebview.js b/src/components/services/content/ServiceWebview.js
index abbf21dee..c146abf4e 100644
--- a/src/components/services/content/ServiceWebview.js
+++ b/src/components/services/content/ServiceWebview.js
@@ -65,6 +65,7 @@ export default class ServiceWebview extends Component {
65 65
66 const webviewClasses = classnames({ 66 const webviewClasses = classnames({
67 services__webview: true, 67 services__webview: true,
68 'services__webview-wrapper': true,
68 'is-active': service.isActive, 69 'is-active': service.isActive,
69 'services__webview--force-repaint': this.state.forceRepaint, 70 'services__webview--force-repaint': this.state.forceRepaint,
70 }); 71 });
@@ -85,29 +86,29 @@ export default class ServiceWebview extends Component {
85 reload={reload} 86 reload={reload}
86 /> 87 />
87 )} 88 )}
88 {!service.isEnabled && ( 89 {!service.isEnabled ? (
89 <ServiceDisabled 90 <ServiceDisabled
90 name={service.recipe.name} 91 name={service.recipe.name}
91 webview={service.webview} 92 webview={service.webview}
92 enable={enable} 93 enable={enable}
93 /> 94 />
95 ) : (
96 <Webview
97 ref={(element) => { this.webview = element; }}
98 autosize
99 src={service.url}
100 preload="./webview/plugin.js"
101 partition={`persist:service-${service.id}`}
102 onDidAttach={() => setWebviewReference({
103 serviceId: service.id,
104 webview: this.webview.view,
105 })}
106 onUpdateTargetUrl={this.updateTargetUrl}
107 useragent={service.userAgent}
108 muted={isAppMuted || service.isMuted}
109 allowpopups
110 />
94 )} 111 )}
95 <Webview
96 ref={(element) => { this.webview = element; }}
97 autosize
98 src={service.url}
99 preload="./webview/plugin.js"
100 partition={`persist:service-${service.id}`}
101 onDidAttach={() => setWebviewReference({
102 serviceId: service.id,
103 webview: this.webview.view,
104 })}
105 onUpdateTargetUrl={this.updateTargetUrl}
106 useragent={service.userAgent}
107 muted={isAppMuted || service.isMuted}
108 disablewebsecurity
109 allowpopups
110 />
111 {statusBar} 112 {statusBar}
112 </div> 113 </div>
113 ); 114 );
diff --git a/src/components/services/content/WebviewCrashHandler.js b/src/components/services/content/WebviewCrashHandler.js
index d48152c18..d3e6951f3 100644
--- a/src/components/services/content/WebviewCrashHandler.js
+++ b/src/components/services/content/WebviewCrashHandler.js
@@ -62,7 +62,7 @@ export default class WebviewCrashHandler extends Component {
62 const { intl } = this.context; 62 const { intl } = this.context;
63 63
64 return ( 64 return (
65 <div className="services__crash-handler"> 65 <div className="services__info-layer">
66 <h1>{intl.formatMessage(messages.headline)}</h1> 66 <h1>{intl.formatMessage(messages.headline)}</h1>
67 <p>{intl.formatMessage(messages.text, { name })}</p> 67 <p>{intl.formatMessage(messages.text, { name })}</p>
68 <Button 68 <Button
diff --git a/src/components/services/tabs/TabBarSortableList.js b/src/components/services/tabs/TabBarSortableList.js
index 2daf55676..489027d57 100644
--- a/src/components/services/tabs/TabBarSortableList.js
+++ b/src/components/services/tabs/TabBarSortableList.js
@@ -17,6 +17,8 @@ class TabBarSortableList extends Component {
17 deleteService: PropTypes.func.isRequired, 17 deleteService: PropTypes.func.isRequired,
18 disableService: PropTypes.func.isRequired, 18 disableService: PropTypes.func.isRequired,
19 enableService: PropTypes.func.isRequired, 19 enableService: PropTypes.func.isRequired,
20 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
21 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
20 } 22 }
21 23
22 render() { 24 render() {
@@ -30,6 +32,8 @@ class TabBarSortableList extends Component {
30 disableService, 32 disableService,
31 enableService, 33 enableService,
32 openSettings, 34 openSettings,
35 showMessageBadgeWhenMutedSetting,
36 showMessageBadgesEvenWhenMuted,
33 } = this.props; 37 } = this.props;
34 38
35 return ( 39 return (
@@ -50,6 +54,8 @@ class TabBarSortableList extends Component {
50 disableService={() => disableService({ serviceId: service.id })} 54 disableService={() => disableService({ serviceId: service.id })}
51 enableService={() => enableService({ serviceId: service.id })} 55 enableService={() => enableService({ serviceId: service.id })}
52 openSettings={openSettings} 56 openSettings={openSettings}
57 showMessageBadgeWhenMutedSetting={showMessageBadgeWhenMutedSetting}
58 showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted}
53 /> 59 />
54 ))} 60 ))}
55 {/* <li> 61 {/* <li>
diff --git a/src/components/services/tabs/TabItem.js b/src/components/services/tabs/TabItem.js
index a7136c43f..7aed8fda7 100644
--- a/src/components/services/tabs/TabItem.js
+++ b/src/components/services/tabs/TabItem.js
@@ -63,6 +63,8 @@ class TabItem extends Component {
63 deleteService: PropTypes.func.isRequired, 63 deleteService: PropTypes.func.isRequired,
64 disableService: PropTypes.func.isRequired, 64 disableService: PropTypes.func.isRequired,
65 enableService: PropTypes.func.isRequired, 65 enableService: PropTypes.func.isRequired,
66 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
67 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
66 }; 68 };
67 69
68 static contextTypes = { 70 static contextTypes = {
@@ -81,6 +83,8 @@ class TabItem extends Component {
81 disableService, 83 disableService,
82 enableService, 84 enableService,
83 openSettings, 85 openSettings,
86 showMessageBadgeWhenMutedSetting,
87 showMessageBadgesEvenWhenMuted,
84 } = this.props; 88 } = this.props;
85 const { intl } = this.context; 89 const { intl } = this.context;
86 90
@@ -121,6 +125,26 @@ class TabItem extends Component {
121 }]; 125 }];
122 const menu = Menu.buildFromTemplate(menuTemplate); 126 const menu = Menu.buildFromTemplate(menuTemplate);
123 127
128 let notificationBadge = null;
129 if ((showMessageBadgeWhenMutedSetting || service.isNotificationEnabled) && showMessageBadgesEvenWhenMuted && service.isBadgeEnabled) {
130 notificationBadge = (
131 <span>
132 {service.unreadDirectMessageCount > 0 && (
133 <span className="tab-item__message-count">
134 {service.unreadDirectMessageCount}
135 </span>
136 )}
137 {service.unreadIndirectMessageCount > 0
138 && service.unreadDirectMessageCount === 0
139 && service.isIndirectMessageBadgeEnabled && (
140 <span className="tab-item__message-count is-indirect">
141
142 </span>
143 )}
144 </span>
145 );
146 }
147
124 return ( 148 return (
125 <li 149 <li
126 className={classnames({ 150 className={classnames({
@@ -138,18 +162,7 @@ class TabItem extends Component {
138 className="tab-item__icon" 162 className="tab-item__icon"
139 alt="" 163 alt=""
140 /> 164 />
141 {service.unreadDirectMessageCount > 0 && ( 165 {notificationBadge}
142 <span className="tab-item__message-count">
143 {service.unreadDirectMessageCount}
144 </span>
145 )}
146 {service.unreadIndirectMessageCount > 0
147 && service.unreadDirectMessageCount === 0
148 && service.isIndirectMessageBadgeEnabled && (
149 <span className="tab-item__message-count is-indirect">
150
151 </span>
152 )}
153 </li> 166 </li>
154 ); 167 );
155 } 168 }
diff --git a/src/components/services/tabs/Tabbar.js b/src/components/services/tabs/Tabbar.js
index fd4325107..ceb88c51c 100644
--- a/src/components/services/tabs/Tabbar.js
+++ b/src/components/services/tabs/Tabbar.js
@@ -18,6 +18,8 @@ export default class TabBar extends Component {
18 toggleAudio: PropTypes.func.isRequired, 18 toggleAudio: PropTypes.func.isRequired,
19 deleteService: PropTypes.func.isRequired, 19 deleteService: PropTypes.func.isRequired,
20 updateService: PropTypes.func.isRequired, 20 updateService: PropTypes.func.isRequired,
21 showMessageBadgeWhenMutedSetting: PropTypes.bool.isRequired,
22 showMessageBadgesEvenWhenMuted: PropTypes.bool.isRequired,
21 } 23 }
22 24
23 onSortEnd = ({ oldIndex, newIndex }) => { 25 onSortEnd = ({ oldIndex, newIndex }) => {
@@ -30,6 +32,8 @@ export default class TabBar extends Component {
30 reorder({ oldIndex, newIndex }); 32 reorder({ oldIndex, newIndex });
31 }; 33 };
32 34
35 shouldPreventSorting = event => event.target.tagName !== 'LI';
36
33 toggleService = ({ serviceId, isEnabled }) => { 37 toggleService = ({ serviceId, isEnabled }) => {
34 const { updateService } = this.props; 38 const { updateService } = this.props;
35 39
@@ -62,6 +66,8 @@ export default class TabBar extends Component {
62 toggleNotifications, 66 toggleNotifications,
63 toggleAudio, 67 toggleAudio,
64 deleteService, 68 deleteService,
69 showMessageBadgeWhenMutedSetting,
70 showMessageBadgesEvenWhenMuted,
65 } = this.props; 71 } = this.props;
66 72
67 return ( 73 return (
@@ -71,6 +77,7 @@ export default class TabBar extends Component {
71 setActive={setActive} 77 setActive={setActive}
72 onSortEnd={this.onSortEnd} 78 onSortEnd={this.onSortEnd}
73 onSortStart={disableToolTip} 79 onSortStart={disableToolTip}
80 shouldCancelStart={this.shouldPreventSorting}
74 reload={reload} 81 reload={reload}
75 toggleNotifications={toggleNotifications} 82 toggleNotifications={toggleNotifications}
76 toggleAudio={toggleAudio} 83 toggleAudio={toggleAudio}
@@ -82,6 +89,8 @@ export default class TabBar extends Component {
82 axis="y" 89 axis="y"
83 lockAxis="y" 90 lockAxis="y"
84 helperClass="is-reordering" 91 helperClass="is-reordering"
92 showMessageBadgeWhenMutedSetting={showMessageBadgeWhenMutedSetting}
93 showMessageBadgesEvenWhenMuted={showMessageBadgesEvenWhenMuted}
85 /> 94 />
86 </div> 95 </div>
87 ); 96 );
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 75dbdef49..89fa07800 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -28,6 +28,10 @@ const messages = defineMessages({
28 id: 'settings.account.headlineInvoices', 28 id: 'settings.account.headlineInvoices',
29 defaultMessage: '!!Invoices', 29 defaultMessage: '!!Invoices',
30 }, 30 },
31 headlineDangerZone: {
32 id: 'settings.account.headlineDangerZone',
33 defaultMessage: '!!Danger Zone',
34 },
31 manageSubscriptionButtonLabel: { 35 manageSubscriptionButtonLabel: {
32 id: 'settings.account.manageSubscription.label', 36 id: 'settings.account.manageSubscription.label',
33 defaultMessage: '!!!Manage your subscription', 37 defaultMessage: '!!!Manage your subscription',
@@ -72,6 +76,18 @@ const messages = defineMessages({
72 id: 'settings.account.mining.cancel', 76 id: 'settings.account.mining.cancel',
73 defaultMessage: '!!!Cancel mining', 77 defaultMessage: '!!!Cancel mining',
74 }, 78 },
79 deleteAccount: {
80 id: 'settings.account.deleteAccount',
81 defaultMessage: '!!!Delete account',
82 },
83 deleteInfo: {
84 id: 'settings.account.deleteInfo',
85 defaultMessage: '!!!If you don\'t need your Franz account any longer, you can delete your account and all related data here.',
86 },
87 deleteEmailSent: {
88 id: 'settings.account.deleteEmailSent',
89 defaultMessage: '!!!You have received an email with a link to confirm your account deletion. Your account and data cannot be restored!',
90 },
75}); 91});
76 92
77@observer 93@observer
@@ -90,6 +106,9 @@ export default class AccountDashboard extends Component {
90 openExternalUrl: PropTypes.func.isRequired, 106 openExternalUrl: PropTypes.func.isRequired,
91 onCloseSubscriptionWindow: PropTypes.func.isRequired, 107 onCloseSubscriptionWindow: PropTypes.func.isRequired,
92 stopMiner: PropTypes.func.isRequired, 108 stopMiner: PropTypes.func.isRequired,
109 deleteAccount: PropTypes.func.isRequired,
110 isLoadingDeleteAccount: PropTypes.bool.isRequired,
111 isDeleteAccountSuccessful: PropTypes.bool.isRequired,
93 }; 112 };
94 113
95 static contextTypes = { 114 static contextTypes = {
@@ -111,6 +130,9 @@ export default class AccountDashboard extends Component {
111 retryUserInfoRequest, 130 retryUserInfoRequest,
112 onCloseSubscriptionWindow, 131 onCloseSubscriptionWindow,
113 stopMiner, 132 stopMiner,
133 deleteAccount,
134 isLoadingDeleteAccount,
135 isDeleteAccountSuccessful,
114 } = this.props; 136 } = this.props;
115 const { intl } = this.context; 137 const { intl } = this.context;
116 138
@@ -201,7 +223,7 @@ export default class AccountDashboard extends Component {
201 /> 223 />
202 </div> 224 </div>
203 </div> 225 </div>
204 <div className="account__box account__box--last"> 226 <div className="account__box">
205 <h2>{intl.formatMessage(messages.headlineInvoices)}</h2> 227 <h2>{intl.formatMessage(messages.headlineInvoices)}</h2>
206 <table className="invoices"> 228 <table className="invoices">
207 <tbody> 229 <tbody>
@@ -230,7 +252,7 @@ export default class AccountDashboard extends Component {
230 252
231 {user.isMiner && ( 253 {user.isMiner && (
232 <div className="account franz-form"> 254 <div className="account franz-form">
233 <div className="account__box"> 255 <div className="account__box account__box--last">
234 <h2>{intl.formatMessage(messages.headlineSubscription)}</h2> 256 <h2>{intl.formatMessage(messages.headlineSubscription)}</h2>
235 <div className="account__subscription"> 257 <div className="account__subscription">
236 <div> 258 <div>
@@ -267,7 +289,7 @@ export default class AccountDashboard extends Component {
267 <Loader /> 289 <Loader />
268 ) : ( 290 ) : (
269 <div className="account franz-form"> 291 <div className="account franz-form">
270 <div className="account__box account__box--last"> 292 <div className="account__box">
271 <h2>{intl.formatMessage(messages.headlineUpgrade)}</h2> 293 <h2>{intl.formatMessage(messages.headlineUpgrade)}</h2>
272 <SubscriptionForm 294 <SubscriptionForm
273 onCloseWindow={onCloseSubscriptionWindow} 295 onCloseWindow={onCloseSubscriptionWindow}
@@ -276,8 +298,29 @@ export default class AccountDashboard extends Component {
276 </div> 298 </div>
277 ) 299 )
278 )} 300 )}
301
302 <div className="account franz-form">
303 <div className="account__box">
304 <h2>{intl.formatMessage(messages.headlineDangerZone)}</h2>
305 {!isDeleteAccountSuccessful && (
306 <div className="account__subscription">
307 <p>{intl.formatMessage(messages.deleteInfo)}</p>
308 <Button
309 label={intl.formatMessage(messages.deleteAccount)}
310 buttonType="danger"
311 onClick={() => deleteAccount()}
312 loaded={!isLoadingDeleteAccount}
313 />
314 </div>
315 )}
316 {isDeleteAccountSuccessful && (
317 <p>{intl.formatMessage(messages.deleteEmailSent)}</p>
318 )}
319 </div>
320 </div>
279 </div> 321 </div>
280 )} 322 )}
323
281 </div> 324 </div>
282 <ReactTooltip place="right" type="dark" effect="solid" /> 325 <ReactTooltip place="right" type="dark" effect="solid" />
283 </div> 326 </div>
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index 3b21a7765..fea8d682d 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -74,7 +74,6 @@ export default class SettingsNavigation extends Component {
74 <Link 74 <Link
75 to="/auth/logout" 75 to="/auth/logout"
76 className="settings-navigation__link" 76 className="settings-navigation__link"
77 activeClassName="is-active"
78 > 77 >
79 {intl.formatMessage(messages.logout)} 78 {intl.formatMessage(messages.logout)}
80 </Link> 79 </Link>
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 02ea04e35..b6ade5da4 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -9,6 +9,7 @@ import Infobox from '../../ui/Infobox';
9import RecipeItem from './RecipeItem'; 9import 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';
12 13
13const messages = defineMessages({ 14const messages = defineMessages({
14 headline: { 15 headline: {
@@ -35,6 +36,10 @@ const messages = defineMessages({
35 id: 'settings.recipes.servicesSuccessfulAddedInfo', 36 id: 'settings.recipes.servicesSuccessfulAddedInfo',
36 defaultMessage: '!!!Service successfully added', 37 defaultMessage: '!!!Service successfully added',
37 }, 38 },
39 missingService: {
40 id: 'settings.recipes.missingService',
41 defaultMessage: '!!!Missing a service?',
42 },
38}); 43});
39 44
40@observer 45@observer
@@ -96,33 +101,39 @@ export default class RecipesDashboard extends Component {
96 </Infobox> 101 </Infobox>
97 </Appear> 102 </Appear>
98 )} 103 )}
99 {!searchNeedle && ( 104 {/* {!searchNeedle && ( */}
100 <div className="recipes__navigation"> 105 <div className="recipes__navigation">
101 <Link 106 <Link
102 to="/settings/recipes" 107 to="/settings/recipes"
103 className="badge" 108 className="badge"
104 activeClassName="badge--primary" 109 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`}
105 > 110 onClick={() => resetSearch()}
106 {intl.formatMessage(messages.mostPopularRecipes)} 111 >
107 </Link> 112 {intl.formatMessage(messages.mostPopularRecipes)}
113 </Link>
114 <Link
115 to="/settings/recipes/all"
116 className="badge"
117 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`}
118 onClick={() => resetSearch()}
119 >
120 {intl.formatMessage(messages.allRecipes)}
121 </Link>
122 {devRecipesCount > 0 && (
108 <Link 123 <Link
109 to="/settings/recipes/all" 124 to="/settings/recipes/dev"
110 className="badge" 125 className="badge"
111 activeClassName="badge--primary" 126 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`}
127 onClick={() => resetSearch()}
112 > 128 >
113 {intl.formatMessage(messages.allRecipes)} 129 {intl.formatMessage(messages.devRecipes)} ({devRecipesCount})
114 </Link> 130 </Link>
115 {devRecipesCount > 0 && ( 131 )}
116 <Link 132 <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request">
117 to="/settings/recipes/dev" 133 {intl.formatMessage(messages.missingService)} <i className="mdi mdi-open-in-new" />
118 className="badge" 134 </a>
119 activeClassName="badge--primary" 135 </div>
120 > 136 {/* )} */}
121 {intl.formatMessage(messages.devRecipes)} ({devRecipesCount})
122 </Link>
123 )}
124 </div>
125 )}
126 {isLoading ? ( 137 {isLoading ? (
127 <Loader /> 138 <Loader />
128 ) : ( 139 ) : (
diff --git a/src/components/settings/services/EditServiceForm.js b/src/components/settings/services/EditServiceForm.js
index bcbda7773..ee69d53aa 100644
--- a/src/components/settings/services/EditServiceForm.js
+++ b/src/components/settings/services/EditServiceForm.js
@@ -48,6 +48,10 @@ const messages = defineMessages({
48 id: 'settings.service.form.tabOnPremise', 48 id: 'settings.service.form.tabOnPremise',
49 defaultMessage: '!!!Self hosted ⭐️', 49 defaultMessage: '!!!Self hosted ⭐️',
50 }, 50 },
51 useHostedService: {
52 id: 'settings.service.form.useHostedService',
53 defaultMessage: '!!!Use the hosted {name} service.',
54 },
51 customUrlValidationError: { 55 customUrlValidationError: {
52 id: 'settings.service.form.customUrlValidationError', 56 id: 'settings.service.form.customUrlValidationError',
53 defaultMessage: '!!!Could not validate custom {name} server.', 57 defaultMessage: '!!!Could not validate custom {name} server.',
@@ -68,6 +72,18 @@ const messages = defineMessages({
68 id: 'settings.service.form.isMutedInfo', 72 id: 'settings.service.form.isMutedInfo',
69 defaultMessage: '!!!When disabled, all notification sounds and audio playback are muted', 73 defaultMessage: '!!!When disabled, all notification sounds and audio playback are muted',
70 }, 74 },
75 headlineNotifications: {
76 id: 'settings.service.form.headlineNotifications',
77 defaultMessage: '!!!Notifications',
78 },
79 headlineBadges: {
80 id: 'settings.service.form.headlineBadges',
81 defaultMessage: '!!!Unread message dadges',
82 },
83 headlineGeneral: {
84 id: 'settings.service.form.headlineGeneral',
85 defaultMessage: '!!!General',
86 },
71}); 87});
72 88
73@observer 89@observer
@@ -109,13 +125,12 @@ export default class EditServiceForm extends Component {
109 this.props.form.submit({ 125 this.props.form.submit({
110 onSuccess: async (form) => { 126 onSuccess: async (form) => {
111 const values = form.values(); 127 const values = form.values();
112
113 let isValid = true; 128 let isValid = true;
114 129
115 if (recipe.validateUrl && values.customUrl) { 130 if (recipe.validateUrl && values.customUrl) {
116 this.setState({ isValidatingCustomUrl: true }); 131 this.setState({ isValidatingCustomUrl: true });
117 try { 132 try {
118 values.customUrl = normalizeUrl(values.customUrl); 133 values.customUrl = normalizeUrl(values.customUrl, { stripWWW: false });
119 isValid = await recipe.validateUrl(values.customUrl); 134 isValid = await recipe.validateUrl(values.customUrl);
120 } catch (err) { 135 } catch (err) {
121 console.warn('ValidateURL', err); 136 console.warn('ValidateURL', err);
@@ -167,6 +182,13 @@ export default class EditServiceForm extends Component {
167 /> 182 />
168 ); 183 );
169 184
185 let activeTabIndex = 0;
186 if (recipe.hasHostedOption && service.team) {
187 activeTabIndex = 1;
188 } else if (recipe.hasHostedOption && service.customUrl) {
189 activeTabIndex = 2;
190 }
191
170 return ( 192 return (
171 <div className="settings__main"> 193 <div className="settings__main">
172 <div className="settings__header"> 194 <div className="settings__header">
@@ -207,11 +229,20 @@ export default class EditServiceForm extends Component {
207 </div> 229 </div>
208 {(recipe.hasTeamId || recipe.hasCustomUrl) && ( 230 {(recipe.hasTeamId || recipe.hasCustomUrl) && (
209 <Tabs 231 <Tabs
210 active={service.customUrl ? 1 : 0} 232 active={activeTabIndex}
211 > 233 >
234 {recipe.hasHostedOption && (
235 <TabItem title={recipe.name}>
236 {intl.formatMessage(messages.useHostedService, { name: recipe.name })}
237 </TabItem>
238 )}
212 {recipe.hasTeamId && ( 239 {recipe.hasTeamId && (
213 <TabItem title={intl.formatMessage(messages.tabHosted)}> 240 <TabItem title={intl.formatMessage(messages.tabHosted)}>
214 <Input field={form.$('team')} suffix={recipe.urlInputSuffix} /> 241 <Input
242 field={form.$('team')}
243 prefix={recipe.urlInputPrefix}
244 suffix={recipe.urlInputSuffix}
245 />
215 </TabItem> 246 </TabItem>
216 )} 247 )}
217 {recipe.hasCustomUrl && ( 248 {recipe.hasCustomUrl && (
@@ -240,20 +271,32 @@ export default class EditServiceForm extends Component {
240 </Tabs> 271 </Tabs>
241 )} 272 )}
242 <div className="settings__options"> 273 <div className="settings__options">
243 <Toggle field={form.$('isNotificationEnabled')} /> 274 <div className="settings__settings-group">
244 {recipe.hasIndirectMessages && ( 275 <h3>{intl.formatMessage(messages.headlineNotifications)}</h3>
245 <div> 276 <Toggle field={form.$('isNotificationEnabled')} />
246 <Toggle field={form.$('isIndirectMessageBadgeEnabled')} /> 277 <Toggle field={form.$('isMuted')} />
247 <p className="settings__help"> 278 <p className="settings__help">
248 {intl.formatMessage(messages.indirectMessageInfo)} 279 {intl.formatMessage(messages.isMutedInfo)}
249 </p> 280 </p>
250 </div> 281 </div>
251 )} 282
252 <Toggle field={form.$('isMuted')} /> 283 <div className="settings__settings-group">
253 <p className="settings__help"> 284 <h3>{intl.formatMessage(messages.headlineBadges)}</h3>
254 {intl.formatMessage(messages.isMutedInfo)} 285 <Toggle field={form.$('isBadgeEnabled')} />
255 </p> 286 {recipe.hasIndirectMessages && form.$('isBadgeEnabled').value && (
256 <Toggle field={form.$('isEnabled')} /> 287 <div>
288 <Toggle field={form.$('isIndirectMessageBadgeEnabled')} />
289 <p className="settings__help">
290 {intl.formatMessage(messages.indirectMessageInfo)}
291 </p>
292 </div>
293 )}
294 </div>
295
296 <div className="settings__settings-group">
297 <h3>{intl.formatMessage(messages.headlineGeneral)}</h3>
298 <Toggle field={form.$('isEnabled')} />
299 </div>
257 </div> 300 </div>
258 {recipe.message && ( 301 {recipe.message && (
259 <p className="settings__message"> 302 <p className="settings__message">
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index ba07b1a5b..ff398aa33 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -9,6 +9,8 @@ import Button from '../../ui/Button';
9import Toggle from '../../ui/Toggle'; 9import Toggle from '../../ui/Toggle';
10import Select from '../../ui/Select'; 10import Select from '../../ui/Select';
11 11
12import { FRANZ_TRANSLATION } from '../../../config';
13
12const messages = defineMessages({ 14const messages = defineMessages({
13 headline: { 15 headline: {
14 id: 'settings.app.headline', 16 id: 'settings.app.headline',
@@ -30,6 +32,14 @@ const messages = defineMessages({
30 id: 'settings.app.headlineAppearance', 32 id: 'settings.app.headlineAppearance',
31 defaultMessage: '!!!Appearance', 33 defaultMessage: '!!!Appearance',
32 }, 34 },
35 headlineAdvanced: {
36 id: 'settings.app.headlineAdvanced',
37 defaultMessage: '!!!Advanced',
38 },
39 translationHelp: {
40 id: 'settings.app.translationHelp',
41 defaultMessage: '!!!Help us to translate Franz into your language.',
42 },
33 buttonSearchForUpdate: { 43 buttonSearchForUpdate: {
34 id: 'settings.app.buttonSearchForUpdate', 44 id: 'settings.app.buttonSearchForUpdate',
35 defaultMessage: '!!!Check for updates', 45 defaultMessage: '!!!Check for updates',
@@ -116,18 +126,38 @@ export default class EditSettingsForm extends Component {
116 onChange={e => this.submit(e)} 126 onChange={e => this.submit(e)}
117 id="form" 127 id="form"
118 > 128 >
119 <h2>{intl.formatMessage(messages.headlineGeneral)}</h2> 129 {/* General */}
130 <h2 id="general">{intl.formatMessage(messages.headlineGeneral)}</h2>
120 <Toggle field={form.$('autoLaunchOnStart')} /> 131 <Toggle field={form.$('autoLaunchOnStart')} />
121 <Toggle field={form.$('runInBackground')} /> 132 <Toggle field={form.$('runInBackground')} />
122 <Toggle field={form.$('enableSystemTray')} /> 133 <Toggle field={form.$('enableSystemTray')} />
123 {process.platform === 'win32' && ( 134 {process.platform === 'win32' && (
124 <Toggle field={form.$('minimizeToSystemTray')} /> 135 <Toggle field={form.$('minimizeToSystemTray')} />
125 )} 136 )}
126 <h2>{intl.formatMessage(messages.headlineAppearance)}</h2> 137
138 {/* Appearance */}
139 <h2 id="apperance">{intl.formatMessage(messages.headlineAppearance)}</h2>
127 <Toggle field={form.$('showDisabledServices')} /> 140 <Toggle field={form.$('showDisabledServices')} />
128 <h2>{intl.formatMessage(messages.headlineLanguage)}</h2> 141 <Toggle field={form.$('showMessageBadgeWhenMuted')} />
142
143 {/* Language */}
144 <h2 id="language">{intl.formatMessage(messages.headlineLanguage)}</h2>
129 <Select field={form.$('locale')} showLabel={false} /> 145 <Select field={form.$('locale')} showLabel={false} />
130 <h2>{intl.formatMessage(messages.headlineUpdates)}</h2> 146 <a
147 href={FRANZ_TRANSLATION}
148 target="_blank"
149 className="link"
150 >
151 {intl.formatMessage(messages.translationHelp)} <i className="mdi mdi-open-in-new" />
152 </a>
153
154 {/* Advanced */}
155 <h2 id="advanced">{intl.formatMessage(messages.headlineAdvanced)}</h2>
156 <Toggle field={form.$('enableSpellchecking')} />
157 {/* <Select field={form.$('spellcheckingLanguage')} /> */}
158
159 {/* Updates */}
160 <h2 id="updates">{intl.formatMessage(messages.headlineUpdates)}</h2>
131 {updateIsReadyToInstall ? ( 161 {updateIsReadyToInstall ? (
132 <Button 162 <Button
133 label={intl.formatMessage(messages.buttonInstallUpdate)} 163 label={intl.formatMessage(messages.buttonInstallUpdate)}
diff --git a/src/components/ui/AppLoader.js b/src/components/ui/AppLoader.js
index 64a212969..ac3cdcb05 100644
--- a/src/components/ui/AppLoader.js
+++ b/src/components/ui/AppLoader.js
@@ -8,7 +8,7 @@ export default function () {
8 <div className="app-loader"> 8 <div className="app-loader">
9 <Appear> 9 <Appear>
10 <h1 className="app-loader__title">Franz</h1> 10 <h1 className="app-loader__title">Franz</h1>
11 <Loader /> 11 <Loader color="#FFF" />
12 </Appear> 12 </Appear>
13 </div> 13 </div>
14 ); 14 );
diff --git a/src/components/ui/Button.js b/src/components/ui/Button.js
index 07e94192f..554206cb7 100644
--- a/src/components/ui/Button.js
+++ b/src/components/ui/Button.js
@@ -68,7 +68,7 @@ export default class Button extends Component {
68 loaded={loaded} 68 loaded={loaded}
69 lines={10} 69 lines={10}
70 scale={0.4} 70 scale={0.4}
71 color={buttonType === '' ? '#FFF' : '#373a3c'} 71 color={buttonType !== 'secondary' ? '#FFF' : '#373a3c'}
72 component="span" 72 component="span"
73 /> 73 />
74 {label} 74 {label}
diff --git a/src/components/ui/InfoBar.js b/src/components/ui/InfoBar.js
index aea2bd888..84a5f1446 100644
--- a/src/components/ui/InfoBar.js
+++ b/src/components/ui/InfoBar.js
@@ -61,10 +61,13 @@ export default class InfoBar extends Component {
61 [`${className}`]: true, 61 [`${className}`]: true,
62 })} 62 })}
63 > 63 >
64 <div onClick={onClick} className="info-bar__content"> 64 <div className="info-bar__content">
65 {children} 65 {children}
66 {ctaLabel && ( 66 {ctaLabel && (
67 <button className="info-bar__cta"> 67 <button
68 className="info-bar__cta"
69 onClick={onClick}
70 >
68 <Loader 71 <Loader
69 loaded={!ctaLoading} 72 loaded={!ctaLoading}
70 lines={10} 73 lines={10}
diff --git a/src/components/ui/Loader.js b/src/components/ui/Loader.js
index e4fbd96a2..f73296bb6 100644
--- a/src/components/ui/Loader.js
+++ b/src/components/ui/Loader.js
@@ -9,12 +9,14 @@ export default class LoaderComponent extends Component {
9 children: oneOrManyChildElements, 9 children: oneOrManyChildElements,
10 loaded: PropTypes.bool, 10 loaded: PropTypes.bool,
11 className: PropTypes.string, 11 className: PropTypes.string,
12 color: PropTypes.string,
12 }; 13 };
13 14
14 static defaultProps = { 15 static defaultProps = {
15 children: null, 16 children: null,
16 loaded: false, 17 loaded: false,
17 className: '', 18 className: '',
19 color: '#373a3c',
18 }; 20 };
19 21
20 render() { 22 render() {
@@ -22,6 +24,7 @@ export default class LoaderComponent extends Component {
22 children, 24 children,
23 loaded, 25 loaded,
24 className, 26 className,
27 color,
25 } = this.props; 28 } = this.props;
26 29
27 return ( 30 return (
@@ -30,7 +33,7 @@ export default class LoaderComponent extends Component {
30 // lines={10} 33 // lines={10}
31 width={4} 34 width={4}
32 scale={0.6} 35 scale={0.6}
33 color="#373a3c" 36 color={color}
34 component="span" 37 component="span"
35 className={className} 38 className={className}
36 > 39 >
diff --git a/src/components/ui/Subscription.js b/src/components/ui/Subscription.js
index fe0925a26..8bff72095 100644
--- a/src/components/ui/Subscription.js
+++ b/src/components/ui/Subscription.js
@@ -93,6 +93,10 @@ const messages = defineMessages({
93 id: 'subscription.mining.moreInformation', 93 id: 'subscription.mining.moreInformation',
94 defaultMessage: '!!!Get more information about this plan', 94 defaultMessage: '!!!Get more information about this plan',
95 }, 95 },
96 euTaxInfo: {
97 id: 'subscription.euTaxInfo',
98 defaultMessage: '!!!EU residents: local sales tax may apply',
99 },
96}); 100});
97 101
98@observer 102@observer
@@ -144,14 +148,18 @@ export default class SubscriptionForm extends Component {
144 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'year') 148 label: `€ ${Object.hasOwnProperty.call(this.props.plan, 'year')
145 ? `${this.props.plan.year.price} / ${intl.formatMessage(messages.typeYearly)}` 149 ? `${this.props.plan.year.price} / ${intl.formatMessage(messages.typeYearly)}`
146 : 'yearly'}`, 150 : 'yearly'}`,
147 }, {
148 value: 'mining',
149 label: intl.formatMessage(messages.typeMining),
150 }], 151 }],
151 }, 152 },
152 }, 153 },
153 }; 154 };
154 155
156 if (this.props.plan.miner) {
157 form.fields.paymentTier.options.push({
158 value: 'mining',
159 label: intl.formatMessage(messages.typeMining),
160 });
161 }
162
155 if (this.props.showSkipOption) { 163 if (this.props.showSkipOption) {
156 form.fields.paymentTier.options.unshift({ 164 form.fields.paymentTier.options.unshift({
157 value: 'skip', 165 value: 'skip',
@@ -259,6 +267,11 @@ export default class SubscriptionForm extends Component {
259 onClick={() => handlePayment(this.form.$('paymentTier').value)} 267 onClick={() => handlePayment(this.form.$('paymentTier').value)}
260 /> 268 />
261 )} 269 )}
270 {this.form.$('paymentTier').value !== 'skip' && this.form.$('paymentTier').value !== 'mining' && (
271 <p className="legal">
272 {intl.formatMessage(messages.euTaxInfo)}
273 </p>
274 )}
262 </Loader> 275 </Loader>
263 ); 276 );
264 } 277 }
diff --git a/src/components/ui/SubscriptionPopup.js b/src/components/ui/SubscriptionPopup.js
index 5aae2c47a..528d02907 100644
--- a/src/components/ui/SubscriptionPopup.js
+++ b/src/components/ui/SubscriptionPopup.js
@@ -58,7 +58,6 @@ export default class SubscriptionPopup extends Component {
58 58
59 autosize 59 autosize
60 src={encodeURI(url)} 60 src={encodeURI(url)}
61 disablewebsecurity
62 onDidNavigate={completeCheck} 61 onDidNavigate={completeCheck}
63 // onNewWindow={(event, url, frameName, options) => 62 // onNewWindow={(event, url, frameName, options) =>
64 // openWindow({ event, url, frameName, options })} 63 // openWindow({ event, url, frameName, options })}