aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/settings
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-06-14 17:21:33 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-06-14 17:21:33 +0200
commitb0e2f5cb5ea7109a81b1f9404fed084a25996efb (patch)
tree1df0700fa627a10971db62421bf6383cf3ce4080 /src/components/settings
parentRestrict services with customURL when not premium user (diff)
parentFix issue with dev recipe list (diff)
downloadferdium-app-b0e2f5cb5ea7109a81b1f9404fed084a25996efb.tar.gz
ferdium-app-b0e2f5cb5ea7109a81b1f9404fed084a25996efb.tar.zst
ferdium-app-b0e2f5cb5ea7109a81b1f9404fed084a25996efb.zip
Merge branch 'feature/3rd-party-limit' into feature/new-pricing
Diffstat (limited to 'src/components/settings')
-rw-r--r--src/components/settings/recipes/RecipeItem.js2
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js192
2 files changed, 157 insertions, 37 deletions
diff --git a/src/components/settings/recipes/RecipeItem.js b/src/components/settings/recipes/RecipeItem.js
index 3bb0852b2..12e3775f6 100644
--- a/src/components/settings/recipes/RecipeItem.js
+++ b/src/components/settings/recipes/RecipeItem.js
@@ -19,7 +19,7 @@ export default @observer class RecipeItem extends Component {
19 className="recipe-teaser" 19 className="recipe-teaser"
20 onClick={onClick} 20 onClick={onClick}
21 > 21 >
22 {recipe.local && ( 22 {recipe.isDevRecipe && (
23 <span className="recipe-teaser__dev-badge">dev</span> 23 <span className="recipe-teaser__dev-badge">dev</span>
24 )} 24 )}
25 <img 25 <img
diff --git a/src/components/settings/recipes/RecipesDashboard.js b/src/components/settings/recipes/RecipesDashboard.js
index 862bd4a27..ed4a429db 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -4,6 +4,9 @@ import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import { Link } from 'react-router'; 5import { Link } from 'react-router';
6 6
7import { Button, Input } from '@meetfranz/forms';
8import injectSheet from 'react-jss';
9import { H3, H2, ProBadge } from '@meetfranz/ui';
7import SearchInput from '../../ui/SearchInput'; 10import SearchInput from '../../ui/SearchInput';
8import Infobox from '../../ui/Infobox'; 11import Infobox from '../../ui/Infobox';
9import RecipeItem from './RecipeItem'; 12import RecipeItem from './RecipeItem';
@@ -11,6 +14,7 @@ import Loader from '../../ui/Loader';
11import Appear from '../../ui/effects/Appear'; 14import Appear from '../../ui/effects/Appear';
12import { FRANZ_SERVICE_REQUEST } from '../../../config'; 15import { FRANZ_SERVICE_REQUEST } from '../../../config';
13import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; 16import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox';
17import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
14 18
15const messages = defineMessages({ 19const messages = defineMessages({
16 headline: { 20 headline: {
@@ -29,9 +33,9 @@ const messages = defineMessages({
29 id: 'settings.recipes.all', 33 id: 'settings.recipes.all',
30 defaultMessage: '!!!All services', 34 defaultMessage: '!!!All services',
31 }, 35 },
32 devRecipes: { 36 customRecipes: {
33 id: 'settings.recipes.dev', 37 id: 'settings.recipes.custom',
34 defaultMessage: '!!!Development', 38 defaultMessage: '!!!Custom Services',
35 }, 39 },
36 nothingFound: { 40 nothingFound: {
37 id: 'settings.recipes.nothingFound', 41 id: 'settings.recipes.nothingFound',
@@ -45,9 +49,61 @@ const messages = defineMessages({
45 id: 'settings.recipes.missingService', 49 id: 'settings.recipes.missingService',
46 defaultMessage: '!!!Missing a service?', 50 defaultMessage: '!!!Missing a service?',
47 }, 51 },
52 customRecipeIntro: {
53 id: 'settings.recipes.customService.intro',
54 defaultMessage: '!!!To add a custom service, copy the recipe folder into:',
55 },
56 openFolder: {
57 id: 'settings.recipes.customService.openFolder',
58 defaultMessage: '!!!Open directory',
59 },
60 openDevDocs: {
61 id: 'settings.recipes.customService.openDevDocs',
62 defaultMessage: '!!!Developer Documentation',
63 },
64 headlineCustomRecipes: {
65 id: 'settings.recipes.customService.headline.customRecipes',
66 defaultMessage: '!!!Custom Service Recipes',
67 },
68 headlineCommunityRecipes: {
69 id: 'settings.recipes.customService.headline.communityRecipes',
70 defaultMessage: '!!!Community Services',
71 },
72 headlineDevRecipes: {
73 id: 'settings.recipes.customService.headline.devRecipes',
74 defaultMessage: '!!!Your Development Service Recipes',
75 },
48}); 76});
49 77
50export default @observer class RecipesDashboard extends Component { 78const styles = {
79 devRecipeIntroContainer: {
80 textAlign: 'center',
81 width: '100%',
82 height: 'auto',
83 margin: [40, 0],
84 },
85 path: {
86 marginTop: 20,
87
88 '& > div': {
89 fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace',
90 },
91 },
92 actionContainer: {
93 '& button': {
94 margin: [0, 10],
95 },
96 },
97 devRecipeList: {
98 marginTop: 20,
99 height: 'auto',
100 },
101 proBadge: {
102 marginLeft: '10px !important',
103 },
104};
105
106export default @injectSheet(styles) @observer class RecipesDashboard extends Component {
51 static propTypes = { 107 static propTypes = {
52 recipes: MobxPropTypes.arrayOrObservableArray.isRequired, 108 recipes: MobxPropTypes.arrayOrObservableArray.isRequired,
53 isLoading: PropTypes.bool.isRequired, 109 isLoading: PropTypes.bool.isRequired,
@@ -56,12 +112,18 @@ export default @observer class RecipesDashboard extends Component {
56 searchRecipes: PropTypes.func.isRequired, 112 searchRecipes: PropTypes.func.isRequired,
57 resetSearch: PropTypes.func.isRequired, 113 resetSearch: PropTypes.func.isRequired,
58 serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, 114 serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired,
59 devRecipesCount: PropTypes.number.isRequired,
60 searchNeedle: PropTypes.string, 115 searchNeedle: PropTypes.string,
116 recipeFilter: PropTypes.string,
117 recipeDirectory: PropTypes.string.isRequired,
118 openRecipeDirectory: PropTypes.func.isRequired,
119 openDevDocs: PropTypes.func.isRequired,
120 classes: PropTypes.object.isRequired,
121 isCommunityRecipesPremiumFeature: PropTypes.bool.isRequired,
61 }; 122 };
62 123
63 static defaultProps = { 124 static defaultProps = {
64 searchNeedle: '', 125 searchNeedle: '',
126 recipeFilter: 'all',
65 } 127 }
66 128
67 static contextTypes = { 129 static contextTypes = {
@@ -77,11 +139,20 @@ export default @observer class RecipesDashboard extends Component {
77 searchRecipes, 139 searchRecipes,
78 resetSearch, 140 resetSearch,
79 serviceStatus, 141 serviceStatus,
80 devRecipesCount,
81 searchNeedle, 142 searchNeedle,
143 recipeFilter,
144 recipeDirectory,
145 openRecipeDirectory,
146 openDevDocs,
147 classes,
148 isCommunityRecipesPremiumFeature,
82 } = this.props; 149 } = this.props;
83 const { intl } = this.context; 150 const { intl } = this.context;
84 151
152
153 const communityRecipes = recipes.filter(r => !r.isDevRecipe);
154 const devRecipes = recipes.filter(r => r.isDevRecipe);
155
85 return ( 156 return (
86 <div className="settings__main"> 157 <div className="settings__main">
87 <div className="settings__header"> 158 <div className="settings__header">
@@ -124,20 +195,14 @@ export default @observer class RecipesDashboard extends Component {
124 > 195 >
125 {intl.formatMessage(messages.allRecipes)} 196 {intl.formatMessage(messages.allRecipes)}
126 </Link> 197 </Link>
127 {devRecipesCount > 0 && ( 198 <Link
128 <Link 199 to="/settings/recipes/dev"
129 to="/settings/recipes/dev" 200 className="badge"
130 className="badge" 201 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`}
131 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} 202 onClick={() => resetSearch()}
132 onClick={() => resetSearch()} 203 >
133 > 204 {intl.formatMessage(messages.customRecipes)}
134 {intl.formatMessage(messages.devRecipes)} 205 </Link>
135 {' '}
136(
137 {devRecipesCount}
138)
139 </Link>
140 )}
141 <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request"> 206 <a href={FRANZ_SERVICE_REQUEST} target="_blank" className="link recipes__service-request">
142 {intl.formatMessage(messages.missingService)} 207 {intl.formatMessage(messages.missingService)}
143 {' '} 208 {' '}
@@ -148,23 +213,78 @@ export default @observer class RecipesDashboard extends Component {
148 {isLoading ? ( 213 {isLoading ? (
149 <Loader /> 214 <Loader />
150 ) : ( 215 ) : (
151 <div className="recipes__list"> 216 <>
152 {hasLoadedRecipes && recipes.length === 0 && ( 217 {recipeFilter === 'dev' && (
153 <p className="align-middle settings__empty-state"> 218 <>
154 <span className="emoji"> 219 <H2>
155 <img src="./assets/images/emoji/dontknow.png" alt="" /> 220 {intl.formatMessage(messages.headlineCustomRecipes)}
156 </span> 221 {isCommunityRecipesPremiumFeature && (
157 {intl.formatMessage(messages.nothingFound)} 222 <ProBadge className={classes.proBadge} />
158 </p> 223 )}
224 </H2>
225 <div className={classes.devRecipeIntroContainer}>
226 <p>
227 {intl.formatMessage(messages.customRecipeIntro)}
228 </p>
229 <Input
230 value={recipeDirectory}
231 className={classes.path}
232 showLabel={false}
233 />
234 <div className={classes.actionContainer}>
235 <Button
236 onClick={openRecipeDirectory}
237 buttonType="secondary"
238 label={intl.formatMessage(messages.openFolder)}
239 />
240 <Button
241 onClick={openDevDocs}
242 buttonType="secondary"
243 label={intl.formatMessage(messages.openDevDocs)}
244 />
245 </div>
246 </div>
247 </>
248 )}
249 <PremiumFeatureContainer
250 condition={(recipeFilter === 'dev' && communityRecipes.length > 0) && isCommunityRecipesPremiumFeature}
251 >
252 {recipeFilter === 'dev' && communityRecipes.length > 0 && (
253 <H3>{intl.formatMessage(messages.headlineCommunityRecipes)}</H3>
254 )}
255 <div className="recipes__list">
256 {hasLoadedRecipes && recipes.length === 0 && recipeFilter !== 'dev' && (
257 <p className="align-middle settings__empty-state">
258 <span className="emoji">
259 <img src="./assets/images/emoji/dontknow.png" alt="" />
260 </span>
261 {intl.formatMessage(messages.nothingFound)}
262 </p>
263 )}
264 {communityRecipes.map(recipe => (
265 <RecipeItem
266 key={recipe.id}
267 recipe={recipe}
268 onClick={() => showAddServiceInterface({ recipeId: recipe.id })}
269 />
270 ))}
271 </div>
272 </PremiumFeatureContainer>
273 {recipeFilter === 'dev' && devRecipes.length > 0 && (
274 <div className={classes.devRecipeList}>
275 <H3>{intl.formatMessage(messages.headlineDevRecipes)}</H3>
276 <div className="recipes__list">
277 {devRecipes.map(recipe => (
278 <RecipeItem
279 key={recipe.id}
280 recipe={recipe}
281 onClick={() => showAddServiceInterface({ recipeId: recipe.id })}
282 />
283 ))}
284 </div>
285 </div>
159 )} 286 )}
160 {recipes.map(recipe => ( 287 </>
161 <RecipeItem
162 key={recipe.id}
163 recipe={recipe}
164 onClick={() => showAddServiceInterface({ recipeId: recipe.id })}
165 />
166 ))}
167 </div>
168 )} 288 )}
169 </div> 289 </div>
170 </div> 290 </div>