aboutsummaryrefslogtreecommitdiffstats
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/layout/AppLayout.js14
-rw-r--r--src/components/settings/account/AccountDashboard.js126
-rw-r--r--src/components/settings/navigation/SettingsNavigation.js17
-rw-r--r--src/components/settings/settings/EditSettingsForm.js8
-rw-r--r--src/components/settings/team/TeamDashboard.js152
-rw-r--r--src/components/subscription/SubscriptionForm.js7
6 files changed, 242 insertions, 82 deletions
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index b7f7722dd..b31c00f54 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -16,6 +16,7 @@ import ErrorBoundary from '../util/ErrorBoundary';
16import { isWindows } from '../../environment'; 16import { isWindows } from '../../environment';
17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator'; 17import WorkspaceSwitchingIndicator from '../../features/workspaces/components/WorkspaceSwitchingIndicator';
18import { workspaceStore } from '../../features/workspaces'; 18import { workspaceStore } from '../../features/workspaces';
19import { announcementActions } from '../../features/announcements/actions';
19 20
20function createMarkup(HTMLString) { 21function createMarkup(HTMLString) {
21 return { __html: HTMLString }; 22 return { __html: HTMLString };
@@ -71,6 +72,7 @@ class AppLayout extends Component {
71 // isOnline: PropTypes.bool.isRequired, 72 // isOnline: PropTypes.bool.isRequired,
72 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 73 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
73 appUpdateIsDownloaded: PropTypes.bool.isRequired, 74 appUpdateIsDownloaded: PropTypes.bool.isRequired,
75 nextAppReleaseVersion: PropTypes.string,
74 removeNewsItem: PropTypes.func.isRequired, 76 removeNewsItem: PropTypes.func.isRequired,
75 reloadServicesAfterUpdate: PropTypes.func.isRequired, 77 reloadServicesAfterUpdate: PropTypes.func.isRequired,
76 installAppUpdate: PropTypes.func.isRequired, 78 installAppUpdate: PropTypes.func.isRequired,
@@ -84,6 +86,7 @@ class AppLayout extends Component {
84 86
85 static defaultProps = { 87 static defaultProps = {
86 children: [], 88 children: [],
89 nextAppReleaseVersion: null,
87 }; 90 };
88 91
89 static contextTypes = { 92 static contextTypes = {
@@ -102,6 +105,7 @@ class AppLayout extends Component {
102 news, 105 news,
103 showServicesUpdatedInfoBar, 106 showServicesUpdatedInfoBar,
104 appUpdateIsDownloaded, 107 appUpdateIsDownloaded,
108 nextAppReleaseVersion,
105 removeNewsItem, 109 removeNewsItem,
106 reloadServicesAfterUpdate, 110 reloadServicesAfterUpdate,
107 installAppUpdate, 111 installAppUpdate,
@@ -178,19 +182,23 @@ class AppLayout extends Component {
178 <span className="mdi mdi-information" /> 182 <span className="mdi mdi-information" />
179 {intl.formatMessage(messages.updateAvailable)} 183 {intl.formatMessage(messages.updateAvailable)}
180 {' '} 184 {' '}
181 <a href="https://meetfranz.com/changelog" target="_blank"> 185 <button
186 className="info-bar__inline-button"
187 type="button"
188 onClick={() => announcementActions.show({ targetVersion: nextAppReleaseVersion })}
189 >
182 <u>{intl.formatMessage(messages.changelog)}</u> 190 <u>{intl.formatMessage(messages.changelog)}</u>
183 </a> 191 </button>
184 </InfoBar> 192 </InfoBar>
185 )} 193 )}
186 {isDelayAppScreenVisible && (<DelayApp />)} 194 {isDelayAppScreenVisible && (<DelayApp />)}
187 <BasicAuth /> 195 <BasicAuth />
188 <ShareFranz /> 196 <ShareFranz />
189 {services} 197 {services}
198 {children}
190 </div> 199 </div>
191 </div> 200 </div>
192 </div> 201 </div>
193 {children}
194 </div> 202 </div>
195 </ErrorBoundary> 203 </ErrorBoundary>
196 ); 204 );
diff --git a/src/components/settings/account/AccountDashboard.js b/src/components/settings/account/AccountDashboard.js
index 181b95c8c..3f6964b6b 100644
--- a/src/components/settings/account/AccountDashboard.js
+++ b/src/components/settings/account/AccountDashboard.js
@@ -3,12 +3,11 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import ReactTooltip from 'react-tooltip'; 5import ReactTooltip from 'react-tooltip';
6import moment from 'moment'; 6import { ProBadge } from '@meetfranz/ui';
7 7
8import Loader from '../../ui/Loader'; 8import Loader from '../../ui/Loader';
9import Button from '../../ui/Button'; 9import Button from '../../ui/Button';
10import Infobox from '../../ui/Infobox'; 10import Infobox from '../../ui/Infobox';
11import Link from '../../ui/Link';
12import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen'; 11import SubscriptionForm from '../../../containers/subscription/SubscriptionFormScreen';
13 12
14const messages = defineMessages({ 13const messages = defineMessages({
@@ -24,10 +23,6 @@ const messages = defineMessages({
24 id: 'settings.account.headlineUpgrade', 23 id: 'settings.account.headlineUpgrade',
25 defaultMessage: '!!!Upgrade your Account', 24 defaultMessage: '!!!Upgrade your Account',
26 }, 25 },
27 headlineInvoices: {
28 id: 'settings.account.headlineInvoices',
29 defaultMessage: '!!Invoices',
30 },
31 headlineDangerZone: { 26 headlineDangerZone: {
32 id: 'settings.account.headlineDangerZone', 27 id: 'settings.account.headlineDangerZone',
33 defaultMessage: '!!Danger Zone', 28 defaultMessage: '!!Danger Zone',
@@ -48,6 +43,10 @@ const messages = defineMessages({
48 id: 'settings.account.account.editButton', 43 id: 'settings.account.account.editButton',
49 defaultMessage: '!!!Edit Account', 44 defaultMessage: '!!!Edit Account',
50 }, 45 },
46 invoicesButton: {
47 id: 'settings.account.headlineInvoices',
48 defaultMessage: '!!Invoices',
49 },
51 invoiceDownload: { 50 invoiceDownload: {
52 id: 'settings.account.invoiceDownload', 51 id: 'settings.account.invoiceDownload',
53 defaultMessage: '!!!Download', 52 defaultMessage: '!!!Download',
@@ -77,19 +76,17 @@ const messages = defineMessages({
77export default @observer class AccountDashboard extends Component { 76export default @observer class AccountDashboard extends Component {
78 static propTypes = { 77 static propTypes = {
79 user: MobxPropTypes.observableObject.isRequired, 78 user: MobxPropTypes.observableObject.isRequired,
80 orders: MobxPropTypes.arrayOrObservableArray.isRequired,
81 isLoading: PropTypes.bool.isRequired, 79 isLoading: PropTypes.bool.isRequired,
82 isLoadingOrdersInfo: PropTypes.bool.isRequired,
83 isLoadingPlans: PropTypes.bool.isRequired, 80 isLoadingPlans: PropTypes.bool.isRequired,
84 isCreatingPaymentDashboardUrl: PropTypes.bool.isRequired,
85 userInfoRequestFailed: PropTypes.bool.isRequired, 81 userInfoRequestFailed: PropTypes.bool.isRequired,
86 retryUserInfoRequest: PropTypes.func.isRequired, 82 retryUserInfoRequest: PropTypes.func.isRequired,
87 openDashboard: PropTypes.func.isRequired,
88 openExternalUrl: PropTypes.func.isRequired,
89 onCloseSubscriptionWindow: PropTypes.func.isRequired, 83 onCloseSubscriptionWindow: PropTypes.func.isRequired,
90 deleteAccount: PropTypes.func.isRequired, 84 deleteAccount: PropTypes.func.isRequired,
91 isLoadingDeleteAccount: PropTypes.bool.isRequired, 85 isLoadingDeleteAccount: PropTypes.bool.isRequired,
92 isDeleteAccountSuccessful: PropTypes.bool.isRequired, 86 isDeleteAccountSuccessful: PropTypes.bool.isRequired,
87 openEditAccount: PropTypes.func.isRequired,
88 openBilling: PropTypes.func.isRequired,
89 openInvoices: PropTypes.func.isRequired,
93 }; 90 };
94 91
95 static contextTypes = { 92 static contextTypes = {
@@ -99,12 +96,7 @@ export default @observer class AccountDashboard extends Component {
99 render() { 96 render() {
100 const { 97 const {
101 user, 98 user,
102 orders,
103 isLoading, 99 isLoading,
104 isCreatingPaymentDashboardUrl,
105 openDashboard,
106 openExternalUrl,
107 isLoadingOrdersInfo,
108 isLoadingPlans, 100 isLoadingPlans,
109 userInfoRequestFailed, 101 userInfoRequestFailed,
110 retryUserInfoRequest, 102 retryUserInfoRequest,
@@ -112,6 +104,9 @@ export default @observer class AccountDashboard extends Component {
112 deleteAccount, 104 deleteAccount,
113 isLoadingDeleteAccount, 105 isLoadingDeleteAccount,
114 isDeleteAccountSuccessful, 106 isDeleteAccountSuccessful,
107 openEditAccount,
108 openBilling,
109 openInvoices,
115 } = this.props; 110 } = this.props;
116 const { intl } = this.context; 111 const { intl } = this.context;
117 112
@@ -149,80 +144,53 @@ export default @observer class AccountDashboard extends Component {
149 src="./assets/images/logo.svg" 144 src="./assets/images/logo.svg"
150 alt="" 145 alt=""
151 /> 146 />
152 {user.isPremium && (
153 <span
154 className="account__avatar-premium emoji"
155 data-tip="Premium Supporter Account"
156 >
157 <img src="./assets/images/emoji/star.png" alt="" />
158 </span>
159 )}
160 </div> 147 </div>
161 <div className="account__info"> 148 <div className="account__info">
162 <h2> 149 <h2>
163 {`${user.firstname} ${user.lastname}`} 150 <span className="username">{`${user.firstname} ${user.lastname}`}</span>
151 {user.isPremium && (
152 <>
153 {' '}
154 <ProBadge />
155 <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span>
156 </>
157 )}
164 </h2> 158 </h2>
165 {user.organization && `${user.organization}, `} 159 {user.organization && `${user.organization}, `}
166 {user.email} 160 {user.email}
167 <br />
168 {user.isPremium && ( 161 {user.isPremium && (
169 <span className="badge badge--premium">{intl.formatMessage(messages.accountTypePremium)}</span> 162 <div className="manage-user-links">
163 <Button
164 label={intl.formatMessage(messages.accountEditButton)}
165 className="franz-form__button--inverted"
166 onClick={openEditAccount}
167 />
168 {user.isSubscriptionOwner && (
169 <>
170 <Button
171 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
172 className="franz-form__button--inverted"
173 onClick={openBilling}
174 />
175 <Button
176 label={intl.formatMessage(messages.invoicesButton)}
177 className="franz-form__button--inverted"
178 onClick={openInvoices}
179 />
180 </>
181 )}
182 </div>
170 )} 183 )}
171 </div> 184 </div>
172 <Link to="/settings/user/edit" className="button"> 185 {!user.isPremium && (
173 {intl.formatMessage(messages.accountEditButton)} 186 <Button
174 </Link> 187 label={intl.formatMessage(messages.accountEditButton)}
175 {user.emailValidated} 188 className="franz-form__button--inverted"
176 </div> 189 onClick={openEditAccount}
177 </div> 190 />
178 )}
179
180 {user.isSubscriptionOwner && (
181 isLoadingOrdersInfo ? (
182 <Loader />
183 ) : (
184 <div className="account franz-form">
185 {orders.length > 0 && (
186 <Fragment>
187 <div className="account__box">
188 <h2>{intl.formatMessage(messages.headlineSubscription)}</h2>
189 <div className="account__subscription">
190 {orders[0].name}
191 <span className="badge">{orders[0].price}</span>
192 <Button
193 label={intl.formatMessage(messages.manageSubscriptionButtonLabel)}
194 className="account__subscription-button franz-form__button--inverted"
195 loaded={!isCreatingPaymentDashboardUrl}
196 onClick={() => openDashboard()}
197 />
198 </div>
199 </div>
200 <div className="account__box">
201 <h2>{intl.formatMessage(messages.headlineInvoices)}</h2>
202 <table className="invoices">
203 <tbody>
204 {orders.map(order => (
205 <tr key={order.id}>
206 <td className="invoices__date">
207 {moment(order.date).format('DD.MM.YYYY')}
208 </td>
209 <td className="invoices__action">
210 <button
211 type="button"
212 onClick={() => openExternalUrl(order.invoiceUrl)}
213 >
214 {intl.formatMessage(messages.invoiceDownload)}
215 </button>
216 </td>
217 </tr>
218 ))}
219 </tbody>
220 </table>
221 </div>
222 </Fragment>
223 )} 191 )}
224 </div> 192 </div>
225 ) 193 </div>
226 )} 194 )}
227 195
228 {!user.isPremium && ( 196 {!user.isPremium && (
diff --git a/src/components/settings/navigation/SettingsNavigation.js b/src/components/settings/navigation/SettingsNavigation.js
index 993b0a44a..df4b3b3b2 100644
--- a/src/components/settings/navigation/SettingsNavigation.js
+++ b/src/components/settings/navigation/SettingsNavigation.js
@@ -7,6 +7,7 @@ import { ProBadge } from '@meetfranz/ui';
7import Link from '../../ui/Link'; 7import Link from '../../ui/Link';
8import { workspaceStore } from '../../../features/workspaces'; 8import { workspaceStore } from '../../../features/workspaces';
9import UIStore from '../../../stores/UIStore'; 9import UIStore from '../../../stores/UIStore';
10import UserStore from '../../../stores/UserStore';
10 11
11const messages = defineMessages({ 12const messages = defineMessages({
12 availableServices: { 13 availableServices: {
@@ -25,6 +26,10 @@ const messages = defineMessages({
25 id: 'settings.navigation.account', 26 id: 'settings.navigation.account',
26 defaultMessage: '!!!Account', 27 defaultMessage: '!!!Account',
27 }, 28 },
29 team: {
30 id: 'settings.navigation.team',
31 defaultMessage: '!!!Manage Team',
32 },
28 settings: { 33 settings: {
29 id: 'settings.navigation.settings', 34 id: 'settings.navigation.settings',
30 defaultMessage: '!!!Settings', 35 defaultMessage: '!!!Settings',
@@ -43,6 +48,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
43 static propTypes = { 48 static propTypes = {
44 stores: PropTypes.shape({ 49 stores: PropTypes.shape({
45 ui: PropTypes.instanceOf(UIStore).isRequired, 50 ui: PropTypes.instanceOf(UIStore).isRequired,
51 user: PropTypes.instanceOf(UserStore).isRequired,
46 }).isRequired, 52 }).isRequired,
47 serviceCount: PropTypes.number.isRequired, 53 serviceCount: PropTypes.number.isRequired,
48 workspaceCount: PropTypes.number.isRequired, 54 workspaceCount: PropTypes.number.isRequired,
@@ -55,6 +61,7 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
55 render() { 61 render() {
56 const { serviceCount, workspaceCount, stores } = this.props; 62 const { serviceCount, workspaceCount, stores } = this.props;
57 const { isDarkThemeActive } = stores.ui; 63 const { isDarkThemeActive } = stores.ui;
64 const { router, user } = stores;
58 const { intl } = this.context; 65 const { intl } = this.context;
59 66
60 return ( 67 return (
@@ -98,6 +105,16 @@ export default @inject('stores') @observer class SettingsNavigation extends Comp
98 {intl.formatMessage(messages.account)} 105 {intl.formatMessage(messages.account)}
99 </Link> 106 </Link>
100 <Link 107 <Link
108 to="/settings/team"
109 className="settings-navigation__link"
110 activeClassName="is-active"
111 >
112 {intl.formatMessage(messages.team)}
113 {!user.data.isPremium && (
114 <ProBadge inverted={!isDarkThemeActive && router.location.pathname === '/settings/team'} />
115 )}
116 </Link>
117 <Link
101 to="/settings/app" 118 to="/settings/app"
102 className="settings-navigation__link" 119 className="settings-navigation__link"
103 activeClassName="is-active" 120 activeClassName="is-active"
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js
index 8429d0ecb..efd453356 100644
--- a/src/components/settings/settings/EditSettingsForm.js
+++ b/src/components/settings/settings/EditSettingsForm.js
@@ -81,6 +81,10 @@ const messages = defineMessages({
81 id: 'settings.app.restartRequired', 81 id: 'settings.app.restartRequired',
82 defaultMessage: '!!!Changes require restart', 82 defaultMessage: '!!!Changes require restart',
83 }, 83 },
84 languageDisclaimer: {
85 id: 'settings.app.languageDisclaimer',
86 defaultMessage: '!!!Official translations are English & German. All other languages are community based translations.',
87 },
84}); 88});
85 89
86export default @observer class EditSettingsForm extends Component { 90export default @observer class EditSettingsForm extends Component {
@@ -239,6 +243,10 @@ export default @observer class EditSettingsForm extends Component {
239 {intl.formatMessage(messages.currentVersion)} 243 {intl.formatMessage(messages.currentVersion)}
240 {' '} 244 {' '}
241 {remote.app.getVersion()} 245 {remote.app.getVersion()}
246 <p className="settings__message">
247 <span className="mdi mdi-information" />
248 {intl.formatMessage(messages.languageDisclaimer)}
249 </p>
242 </form> 250 </form>
243 </div> 251 </div>
244 </div> 252 </div>
diff --git a/src/components/settings/team/TeamDashboard.js b/src/components/settings/team/TeamDashboard.js
new file mode 100644
index 000000000..82c517fcb
--- /dev/null
+++ b/src/components/settings/team/TeamDashboard.js
@@ -0,0 +1,152 @@
1import React, { Component } from 'react';
2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl';
5import ReactTooltip from 'react-tooltip';
6import injectSheet from 'react-jss';
7
8import Loader from '../../ui/Loader';
9import Button from '../../ui/Button';
10import Infobox from '../../ui/Infobox';
11import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
12
13const messages = defineMessages({
14 headline: {
15 id: 'settings.team.headline',
16 defaultMessage: '!!!Team',
17 },
18 contentHeadline: {
19 id: 'settings.team.contentHeadline',
20 defaultMessage: '!!!Franz for Teams',
21 },
22 intro: {
23 id: 'settings.team.intro',
24 defaultMessage: '!!!You and your team use Franz? You can now manage Premium subscriptions for as many colleagues, friends or family members as you want, all from within one account.',
25 },
26 copy: {
27 id: 'settings.team.copy',
28 defaultMessage: '!!!Franz for Teams gives you the option to invite co-workers to your team by sending them email invitations and manage their subscriptions in your account’s preferences. Don’t waste time setting up subscriptions for every team member individually, forget about multiple invoices and different billing cycles - one team to rule them all!',
29 },
30 manageButton: {
31 id: 'settings.team.manageAction',
32 defaultMessage: '!!!Manage your Team on meetfranz.com',
33 },
34 upgradeButton: {
35 id: 'settings.team.upgradeAction',
36 defaultMessage: '!!!Upgrade your Account',
37 },
38});
39
40const styles = {
41 cta: {
42 margin: [40, 'auto'],
43 },
44 container: {
45 display: 'flex',
46 flexDirection: 'column',
47 height: 'auto',
48
49 '@media(min-width: 800px)': {
50 flexDirection: 'row',
51 },
52 },
53 content: {
54 height: 'auto',
55 order: 1,
56
57 '@media(min-width: 800px)': {
58 order: 0,
59 },
60 },
61 image: {
62 display: 'block',
63 height: 150,
64 order: 0,
65 margin: [0, 'auto', 40, 'auto'],
66
67 '@media(min-width: 800px)': {
68 marginLeft: 40,
69 order: 1,
70 },
71 },
72};
73
74
75export default @injectSheet(styles) @observer class TeamDashboard extends Component {
76 static propTypes = {
77 isLoading: PropTypes.bool.isRequired,
78 userInfoRequestFailed: PropTypes.bool.isRequired,
79 retryUserInfoRequest: PropTypes.func.isRequired,
80 openTeamManagement: PropTypes.func.isRequired,
81 classes: PropTypes.object.isRequired,
82 };
83
84 static contextTypes = {
85 intl: intlShape,
86 };
87
88 render() {
89 const {
90 isLoading,
91 userInfoRequestFailed,
92 retryUserInfoRequest,
93 openTeamManagement,
94 classes,
95 } = this.props;
96 const { intl } = this.context;
97
98 return (
99 <div className="settings__main">
100 <div className="settings__header">
101 <span className="settings__header-item">
102 {intl.formatMessage(messages.headline)}
103 </span>
104 </div>
105 <div className="settings__body">
106 {isLoading && (
107 <Loader />
108 )}
109
110 {!isLoading && userInfoRequestFailed && (
111 <Infobox
112 icon="alert"
113 type="danger"
114 ctaLabel={intl.formatMessage(messages.tryReloadUserInfoRequest)}
115 ctaLoading={isLoading}
116 ctaOnClick={retryUserInfoRequest}
117 >
118 {intl.formatMessage(messages.userInfoRequestFailed)}
119 </Infobox>
120 )}
121
122 {!userInfoRequestFailed && (
123 <>
124 {!isLoading && (
125 <>
126 <PremiumFeatureContainer>
127 <>
128 <h1>{intl.formatMessage(messages.contentHeadline)}</h1>
129 <div className={classes.container}>
130 <div className={classes.content}>
131 <p>{intl.formatMessage(messages.intro)}</p>
132 <p>{intl.formatMessage(messages.copy)}</p>
133 </div>
134 <img className={classes.image} src="https://cdn.franzinfra.com/announcements/assets/teams.png" alt="Franz for Teams" />
135 </div>
136 <Button
137 label={intl.formatMessage(messages.manageButton)}
138 onClick={openTeamManagement}
139 className={classes.cta}
140 />
141 </>
142 </PremiumFeatureContainer>
143 </>
144 )}
145 </>
146 )}
147 </div>
148 <ReactTooltip place="right" type="dark" effect="solid" />
149 </div>
150 );
151 }
152}
diff --git a/src/components/subscription/SubscriptionForm.js b/src/components/subscription/SubscriptionForm.js
index 7a818d100..50f1e0522 100644
--- a/src/components/subscription/SubscriptionForm.js
+++ b/src/components/subscription/SubscriptionForm.js
@@ -51,6 +51,10 @@ const messages = defineMessages({
51 id: 'subscription.features.spellchecker', 51 id: 'subscription.features.spellchecker',
52 defaultMessage: '!!!Support for Spellchecker', 52 defaultMessage: '!!!Support for Spellchecker',
53 }, 53 },
54 workspaces: {
55 id: 'subscription.features.workspaces',
56 defaultMessage: '!!!Organize your services in workspaces',
57 },
54 ads: { 58 ads: {
55 id: 'subscription.features.ads', 59 id: 'subscription.features.ads',
56 defaultMessage: '!!!No ads, ever!', 60 defaultMessage: '!!!No ads, ever!',
@@ -171,6 +175,9 @@ export default @observer class SubscriptionForm extends Component {
171 {intl.formatMessage(messages.proxy)} 175 {intl.formatMessage(messages.proxy)}
172 </li> 176 </li>
173 <li> 177 <li>
178 {intl.formatMessage(messages.workspaces)}
179 </li>
180 <li>
174 {intl.formatMessage(messages.ads)} 181 {intl.formatMessage(messages.ads)}
175 </li> 182 </li>
176 </ul> 183 </ul>