diff options
author | Stefan Malzner <stefan@adlk.io> | 2019-06-14 17:21:33 +0200 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2019-06-14 17:21:33 +0200 |
commit | b0e2f5cb5ea7109a81b1f9404fed084a25996efb (patch) | |
tree | 1df0700fa627a10971db62421bf6383cf3ce4080 /src/components/settings/recipes/RecipesDashboard.js | |
parent | Restrict services with customURL when not premium user (diff) | |
parent | Fix issue with dev recipe list (diff) | |
download | ferdium-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/recipes/RecipesDashboard.js')
-rw-r--r-- | src/components/settings/recipes/RecipesDashboard.js | 192 |
1 files changed, 156 insertions, 36 deletions
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'; | |||
4 | import { defineMessages, intlShape } from 'react-intl'; | 4 | import { defineMessages, intlShape } from 'react-intl'; |
5 | import { Link } from 'react-router'; | 5 | import { Link } from 'react-router'; |
6 | 6 | ||
7 | import { Button, Input } from '@meetfranz/forms'; | ||
8 | import injectSheet from 'react-jss'; | ||
9 | import { H3, H2, ProBadge } from '@meetfranz/ui'; | ||
7 | import SearchInput from '../../ui/SearchInput'; | 10 | import SearchInput from '../../ui/SearchInput'; |
8 | import Infobox from '../../ui/Infobox'; | 11 | import Infobox from '../../ui/Infobox'; |
9 | import RecipeItem from './RecipeItem'; | 12 | import RecipeItem from './RecipeItem'; |
@@ -11,6 +14,7 @@ import Loader from '../../ui/Loader'; | |||
11 | import Appear from '../../ui/effects/Appear'; | 14 | import Appear from '../../ui/effects/Appear'; |
12 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; | 15 | import { FRANZ_SERVICE_REQUEST } from '../../../config'; |
13 | import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; | 16 | import LimitReachedInfobox from '../../../features/serviceLimit/components/LimitReachedInfobox'; |
17 | import PremiumFeatureContainer from '../../ui/PremiumFeatureContainer'; | ||
14 | 18 | ||
15 | const messages = defineMessages({ | 19 | const 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 | ||
50 | export default @observer class RecipesDashboard extends Component { | 78 | const 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 | |||
106 | export 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> |