aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/settings
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-05-02 11:27:23 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-05-02 11:27:23 +0200
commitfbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e (patch)
treedfa0a6c32ce62c605bcdbf5538d9dc03725d1f88 /src/components/settings
parentUpdate CHANGELOG.md (diff)
downloadferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.tar.gz
ferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.tar.zst
ferdium-app-fbff4ed90b0137088b1bb92e95f32fc1bfa7bb3e.zip
Add custom recipe limitation
Diffstat (limited to 'src/components/settings')
-rw-r--r--src/components/settings/recipes/RecipeItem.js2
-rw-r--r--src/components/settings/recipes/RecipesDashboard.js194
2 files changed, 159 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 00cd725cf..e2e8121e5 100644
--- a/src/components/settings/recipes/RecipesDashboard.js
+++ b/src/components/settings/recipes/RecipesDashboard.js
@@ -4,12 +4,16 @@ 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';
10import Loader from '../../ui/Loader'; 13import 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';
16import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer';
13 17
14const messages = defineMessages({ 18const messages = defineMessages({
15 headline: { 19 headline: {
@@ -28,9 +32,9 @@ const messages = defineMessages({
28 id: 'settings.recipes.all', 32 id: 'settings.recipes.all',
29 defaultMessage: '!!!All services', 33 defaultMessage: '!!!All services',
30 }, 34 },
31 devRecipes: { 35 customRecipes: {
32 id: 'settings.recipes.dev', 36 id: 'settings.recipes.custom',
33 defaultMessage: '!!!Development', 37 defaultMessage: '!!!Custom Services',
34 }, 38 },
35 nothingFound: { 39 nothingFound: {
36 id: 'settings.recipes.nothingFound', 40 id: 'settings.recipes.nothingFound',
@@ -44,9 +48,61 @@ const messages = defineMessages({
44 id: 'settings.recipes.missingService', 48 id: 'settings.recipes.missingService',
45 defaultMessage: '!!!Missing a service?', 49 defaultMessage: '!!!Missing a service?',
46 }, 50 },
51 customRecipeIntro: {
52 id: 'settings.recipes.customService.intro',
53 defaultMessage: '!!!To add a custom service, copy the recipe folder into:',
54 },
55 openFolder: {
56 id: 'settings.recipes.customService.openFolder',
57 defaultMessage: '!!!Open directory',
58 },
59 openDevDocs: {
60 id: 'settings.recipes.customService.openDevDocs',
61 defaultMessage: '!!!Developer Documentation',
62 },
63 headlineCustomRecipes: {
64 id: 'settings.recipes.customService.headline.customRecipes',
65 defaultMessage: '!!!Custom Service Recipes',
66 },
67 headlineCommunityRecipes: {
68 id: 'settings.recipes.customService.headline.communityRecipes',
69 defaultMessage: '!!!Community Services',
70 },
71 headlineDevRecipes: {
72 id: 'settings.recipes.customService.headline.devRecipes',
73 defaultMessage: '!!!Your Development Service Recipes',
74 },
47}); 75});
48 76
49export default @observer class RecipesDashboard extends Component { 77const styles = {
78 devRecipeIntroContainer: {
79 textAlign: 'center',
80 width: '100%',
81 height: 'auto',
82 margin: [40, 0],
83 },
84 path: {
85 marginTop: 20,
86
87 '& > div': {
88 fontFamily: 'SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace',
89 },
90 },
91 actionContainer: {
92 '& button': {
93 margin: [0, 10],
94 },
95 },
96 devRecipeList: {
97 marginTop: 20,
98 height: 'auto',
99 },
100 proBadge: {
101 marginLeft: '10px !important',
102 },
103};
104
105export default @injectSheet(styles) @observer class RecipesDashboard extends Component {
50 static propTypes = { 106 static propTypes = {
51 recipes: MobxPropTypes.arrayOrObservableArray.isRequired, 107 recipes: MobxPropTypes.arrayOrObservableArray.isRequired,
52 isLoading: PropTypes.bool.isRequired, 108 isLoading: PropTypes.bool.isRequired,
@@ -55,12 +111,19 @@ export default @observer class RecipesDashboard extends Component {
55 searchRecipes: PropTypes.func.isRequired, 111 searchRecipes: PropTypes.func.isRequired,
56 resetSearch: PropTypes.func.isRequired, 112 resetSearch: PropTypes.func.isRequired,
57 serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired, 113 serviceStatus: MobxPropTypes.arrayOrObservableArray.isRequired,
58 devRecipesCount: PropTypes.number.isRequired,
59 searchNeedle: PropTypes.string, 114 searchNeedle: PropTypes.string,
115 recipeFilter: PropTypes.string,
116 recipeDirectory: PropTypes.string.isRequired,
117 openRecipeDirectory: PropTypes.func.isRequired,
118 openDevDocs: PropTypes.func.isRequired,
119 classes: PropTypes.object.isRequired,
120 isCommunityRecipesPremiumFeature: PropTypes.bool.isRequired,
121 isUserPremiumUser: PropTypes.bool.isRequired,
60 }; 122 };
61 123
62 static defaultProps = { 124 static defaultProps = {
63 searchNeedle: '', 125 searchNeedle: '',
126 recipeFilter: 'all',
64 } 127 }
65 128
66 static contextTypes = { 129 static contextTypes = {
@@ -76,11 +139,21 @@ export default @observer class RecipesDashboard extends Component {
76 searchRecipes, 139 searchRecipes,
77 resetSearch, 140 resetSearch,
78 serviceStatus, 141 serviceStatus,
79 devRecipesCount,
80 searchNeedle, 142 searchNeedle,
143 recipeFilter,
144 recipeDirectory,
145 openRecipeDirectory,
146 openDevDocs,
147 classes,
148 isCommunityRecipesPremiumFeature,
149 isUserPremiumUser,
81 } = this.props; 150 } = this.props;
82 const { intl } = this.context; 151 const { intl } = this.context;
83 152
153
154 const communityRecipes = recipes.filter(r => !r.isDevRecipe);
155 const devRecipes = recipes.filter(r => r.isDevRecipe);
156
84 return ( 157 return (
85 <div className="settings__main"> 158 <div className="settings__main">
86 <div className="settings__header"> 159 <div className="settings__header">
@@ -122,20 +195,14 @@ export default @observer class RecipesDashboard extends Component {
122 > 195 >
123 {intl.formatMessage(messages.allRecipes)} 196 {intl.formatMessage(messages.allRecipes)}
124 </Link> 197 </Link>
125 {devRecipesCount > 0 && ( 198 <Link
126 <Link 199 to="/settings/recipes/dev"
127 to="/settings/recipes/dev" 200 className="badge"
128 className="badge" 201 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`}
129 activeClassName={`${!searchNeedle ? 'badge--primary' : ''}`} 202 onClick={() => resetSearch()}
130 onClick={() => resetSearch()} 203 >
131 > 204 {intl.formatMessage(messages.customRecipes)}
132 {intl.formatMessage(messages.devRecipes)} 205 </Link>
133 {' '}
134(
135 {devRecipesCount}
136)
137 </Link>
138 )}
139 <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">
140 {intl.formatMessage(messages.missingService)} 207 {intl.formatMessage(messages.missingService)}
141 {' '} 208 {' '}
@@ -146,23 +213,78 @@ export default @observer class RecipesDashboard extends Component {
146 {isLoading ? ( 213 {isLoading ? (
147 <Loader /> 214 <Loader />
148 ) : ( 215 ) : (
149 <div className="recipes__list"> 216 <>
150 {hasLoadedRecipes && recipes.length === 0 && ( 217 {recipeFilter === 'dev' && (
151 <p className="align-middle settings__empty-state"> 218 <>
152 <span className="emoji"> 219 <H2>
153 <img src="./assets/images/emoji/dontknow.png" alt="" /> 220 {intl.formatMessage(messages.headlineCustomRecipes)}
154 </span> 221 {!isUserPremiumUser && (
155 {intl.formatMessage(messages.nothingFound)} 222 <ProBadge className={classes.proBadge} />
156 </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>
157 )} 286 )}
158 {recipes.map(recipe => ( 287 </>
159 <RecipeItem
160 key={recipe.id}
161 recipe={recipe}
162 onClick={() => showAddServiceInterface({ recipeId: recipe.id })}
163 />
164 ))}
165 </div>
166 )} 288 )}
167 </div> 289 </div>
168 </div> 290 </div>