aboutsummaryrefslogtreecommitdiffstats
path: root/src/containers/settings/RecipesScreen.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/containers/settings/RecipesScreen.tsx')
-rw-r--r--src/containers/settings/RecipesScreen.tsx188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/containers/settings/RecipesScreen.tsx b/src/containers/settings/RecipesScreen.tsx
new file mode 100644
index 000000000..c50ff246e
--- /dev/null
+++ b/src/containers/settings/RecipesScreen.tsx
@@ -0,0 +1,188 @@
1import { readJsonSync } from 'fs-extra';
2import { Component, ReactElement } from 'react';
3import { autorun, IReactionDisposer } from 'mobx';
4import { inject, observer } from 'mobx-react';
5
6import { StoresProps } from 'src/@types/ferdium-components.types';
7import Recipe from 'src/models/Recipe';
8import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard';
9import ErrorBoundary from '../../components/util/ErrorBoundary';
10import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config';
11import { userDataRecipesPath } from '../../environment-remote';
12import { asarRecipesPath } from '../../helpers/asar-helpers';
13import { communityRecipesStore } from '../../features/communityRecipes';
14import RecipePreview from '../../models/RecipePreview';
15import { openPath } from '../../helpers/url-helpers';
16
17interface RecipesScreenProps extends StoresProps {
18 params: {
19 filter?: string | null;
20 };
21}
22
23class RecipesScreen extends Component<RecipesScreenProps> {
24 state: {
25 needle: string | null;
26 currentFilter: string;
27 } = {
28 needle: null,
29 currentFilter: 'featured',
30 };
31
32 autorunDisposer: IReactionDisposer | null = null;
33
34 customRecipes: Recipe[] = [];
35
36 constructor(props: RecipesScreenProps) {
37 super(props);
38
39 this.props.params.filter = this.props.params.filter || null;
40
41 this.customRecipes = readJsonSync(asarRecipesPath('all.json'));
42 }
43
44 componentDidMount(): void {
45 this.autorunDisposer = autorun(() => {
46 const { filter } = this.props.params;
47 const { currentFilter } = this.state;
48
49 if (filter === 'all' && currentFilter !== 'all') {
50 this.setState({ currentFilter: 'all' });
51 } else if (filter === 'featured' && currentFilter !== 'featured') {
52 this.setState({ currentFilter: 'featured' });
53 } else if (filter === 'dev' && currentFilter !== 'dev') {
54 this.setState({ currentFilter: 'dev' });
55 }
56 });
57 }
58
59 componentWillUnmount(): void {
60 this.props.stores.services.resetStatus();
61
62 if (typeof this.autorunDisposer === 'function') {
63 this.autorunDisposer();
64 }
65 }
66
67 searchRecipes(needle: string | null): void {
68 if (needle === '') {
69 this.resetSearch();
70 } else {
71 const { search } = this.props.actions.recipePreview;
72 this.setState({ needle });
73 search({ needle });
74 }
75 }
76
77 _sortByName(recipe1, recipe2): number {
78 if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) {
79 return -1;
80 }
81 if (recipe1.name.toLowerCase() > recipe2.name.toLowerCase()) {
82 return 1;
83 }
84 return 0;
85 }
86
87 prepareRecipes(recipes: RecipePreview[]): RecipePreview[] {
88 return (
89 recipes
90 // Filter out duplicate recipes
91 .filter((recipe, index, self) => {
92 const ids = self.map(rec => rec.id);
93 return ids.indexOf(recipe.id) === index;
94
95 // Sort alphabetically
96 })
97 .sort(this._sortByName)
98 );
99 }
100
101 // Create an array of RecipePreviews from an array of recipe objects
102 createPreviews(recipes: Recipe[]) {
103 return recipes.map((recipe: any) => new RecipePreview(recipe));
104 }
105
106 resetSearch(): void {
107 this.setState({ needle: null });
108 }
109
110 render(): ReactElement {
111 const { recipePreviews, recipes, services } = this.props.stores;
112
113 const { app: appActions, service: serviceActions } = this.props.actions;
114
115 const { filter } = this.props.params;
116 let recipeFilter;
117
118 if (filter === 'all') {
119 recipeFilter = this.prepareRecipes([
120 ...recipePreviews.all,
121 ...this.createPreviews(this.customRecipes),
122 ]);
123 } else if (filter === 'dev') {
124 recipeFilter = communityRecipesStore.communityRecipes;
125 } else {
126 recipeFilter = recipePreviews.featured;
127 }
128 recipeFilter = recipeFilter.sort(this._sortByName);
129
130 const { needle } = this.state;
131 const allRecipes =
132 needle !== null
133 ? this.prepareRecipes([
134 // All search recipes from server
135 ...recipePreviews.searchResults,
136 // All search recipes from local recipes
137 ...this.createPreviews(
138 this.customRecipes.filter(
139 (recipe: Recipe) =>
140 recipe.name.toLowerCase().includes(needle.toLowerCase()) ||
141 (recipe.aliases || []).some(alias =>
142 alias.toLowerCase().includes(needle.toLowerCase()),
143 ),
144 ),
145 ),
146 ]).sort(this._sortByName)
147 : recipeFilter;
148
149 const customWebsiteRecipe = recipePreviews.all.find(
150 service => service.id === CUSTOM_WEBSITE_RECIPE_ID,
151 );
152
153 const isLoading =
154 recipePreviews.featuredRecipePreviewsRequest.isExecuting ||
155 recipePreviews.allRecipePreviewsRequest.isExecuting ||
156 recipes.installRecipeRequest.isExecuting ||
157 recipePreviews.searchRecipePreviewsRequest.isExecuting;
158
159 const recipeDirectory = userDataRecipesPath('dev');
160
161 return (
162 <ErrorBoundary>
163 <RecipesDashboard
164 recipes={allRecipes}
165 customWebsiteRecipe={customWebsiteRecipe}
166 isLoading={isLoading}
167 addedServiceCount={services.all.length}
168 hasLoadedRecipes={
169 recipePreviews.featuredRecipePreviewsRequest.wasExecuted
170 }
171 showAddServiceInterface={serviceActions.showAddServiceInterface}
172 searchRecipes={e => this.searchRecipes(e)}
173 resetSearch={() => this.resetSearch()}
174 searchNeedle={this.state.needle}
175 serviceStatus={services.actionStatus}
176 recipeFilter={filter}
177 recipeDirectory={recipeDirectory}
178 openRecipeDirectory={() => openPath(recipeDirectory)}
179 openDevDocs={() =>
180 appActions.openExternalUrl({ url: FRANZ_DEV_DOCS })
181 }
182 />
183 </ErrorBoundary>
184 );
185 }
186}
187
188export default inject('stores', 'actions')(observer(RecipesScreen));