From 0bf13689d53bd493fb4d0a4213c1801013b5aa8a Mon Sep 17 00:00:00 2001 From: Ricardo Cino Date: Mon, 27 Jun 2022 18:21:31 +0200 Subject: chore: transform containers/settings from js to tsx (#384) --- src/containers/settings/RecipesScreen.tsx | 188 ++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 src/containers/settings/RecipesScreen.tsx (limited to 'src/containers/settings/RecipesScreen.tsx') 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 @@ +import { readJsonSync } from 'fs-extra'; +import { Component, ReactElement } from 'react'; +import { autorun, IReactionDisposer } from 'mobx'; +import { inject, observer } from 'mobx-react'; + +import { StoresProps } from 'src/@types/ferdium-components.types'; +import Recipe from 'src/models/Recipe'; +import RecipesDashboard from '../../components/settings/recipes/RecipesDashboard'; +import ErrorBoundary from '../../components/util/ErrorBoundary'; +import { CUSTOM_WEBSITE_RECIPE_ID, FRANZ_DEV_DOCS } from '../../config'; +import { userDataRecipesPath } from '../../environment-remote'; +import { asarRecipesPath } from '../../helpers/asar-helpers'; +import { communityRecipesStore } from '../../features/communityRecipes'; +import RecipePreview from '../../models/RecipePreview'; +import { openPath } from '../../helpers/url-helpers'; + +interface RecipesScreenProps extends StoresProps { + params: { + filter?: string | null; + }; +} + +class RecipesScreen extends Component { + state: { + needle: string | null; + currentFilter: string; + } = { + needle: null, + currentFilter: 'featured', + }; + + autorunDisposer: IReactionDisposer | null = null; + + customRecipes: Recipe[] = []; + + constructor(props: RecipesScreenProps) { + super(props); + + this.props.params.filter = this.props.params.filter || null; + + this.customRecipes = readJsonSync(asarRecipesPath('all.json')); + } + + componentDidMount(): void { + this.autorunDisposer = autorun(() => { + const { filter } = this.props.params; + const { currentFilter } = this.state; + + if (filter === 'all' && currentFilter !== 'all') { + this.setState({ currentFilter: 'all' }); + } else if (filter === 'featured' && currentFilter !== 'featured') { + this.setState({ currentFilter: 'featured' }); + } else if (filter === 'dev' && currentFilter !== 'dev') { + this.setState({ currentFilter: 'dev' }); + } + }); + } + + componentWillUnmount(): void { + this.props.stores.services.resetStatus(); + + if (typeof this.autorunDisposer === 'function') { + this.autorunDisposer(); + } + } + + searchRecipes(needle: string | null): void { + if (needle === '') { + this.resetSearch(); + } else { + const { search } = this.props.actions.recipePreview; + this.setState({ needle }); + search({ needle }); + } + } + + _sortByName(recipe1, recipe2): number { + if (recipe1.name.toLowerCase() < recipe2.name.toLowerCase()) { + return -1; + } + if (recipe1.name.toLowerCase() > recipe2.name.toLowerCase()) { + return 1; + } + return 0; + } + + prepareRecipes(recipes: RecipePreview[]): RecipePreview[] { + return ( + recipes + // Filter out duplicate recipes + .filter((recipe, index, self) => { + const ids = self.map(rec => rec.id); + return ids.indexOf(recipe.id) === index; + + // Sort alphabetically + }) + .sort(this._sortByName) + ); + } + + // Create an array of RecipePreviews from an array of recipe objects + createPreviews(recipes: Recipe[]) { + return recipes.map((recipe: any) => new RecipePreview(recipe)); + } + + resetSearch(): void { + this.setState({ needle: null }); + } + + render(): ReactElement { + const { recipePreviews, recipes, services } = this.props.stores; + + const { app: appActions, service: serviceActions } = this.props.actions; + + const { filter } = this.props.params; + let recipeFilter; + + if (filter === 'all') { + recipeFilter = this.prepareRecipes([ + ...recipePreviews.all, + ...this.createPreviews(this.customRecipes), + ]); + } else if (filter === 'dev') { + recipeFilter = communityRecipesStore.communityRecipes; + } else { + recipeFilter = recipePreviews.featured; + } + recipeFilter = recipeFilter.sort(this._sortByName); + + const { needle } = this.state; + const allRecipes = + needle !== null + ? this.prepareRecipes([ + // All search recipes from server + ...recipePreviews.searchResults, + // All search recipes from local recipes + ...this.createPreviews( + this.customRecipes.filter( + (recipe: Recipe) => + recipe.name.toLowerCase().includes(needle.toLowerCase()) || + (recipe.aliases || []).some(alias => + alias.toLowerCase().includes(needle.toLowerCase()), + ), + ), + ), + ]).sort(this._sortByName) + : recipeFilter; + + const customWebsiteRecipe = recipePreviews.all.find( + service => service.id === CUSTOM_WEBSITE_RECIPE_ID, + ); + + const isLoading = + recipePreviews.featuredRecipePreviewsRequest.isExecuting || + recipePreviews.allRecipePreviewsRequest.isExecuting || + recipes.installRecipeRequest.isExecuting || + recipePreviews.searchRecipePreviewsRequest.isExecuting; + + const recipeDirectory = userDataRecipesPath('dev'); + + return ( + + this.searchRecipes(e)} + resetSearch={() => this.resetSearch()} + searchNeedle={this.state.needle} + serviceStatus={services.actionStatus} + recipeFilter={filter} + recipeDirectory={recipeDirectory} + openRecipeDirectory={() => openPath(recipeDirectory)} + openDevDocs={() => + appActions.openExternalUrl({ url: FRANZ_DEV_DOCS }) + } + /> + + ); + } +} + +export default inject('stores', 'actions')(observer(RecipesScreen)); -- cgit v1.2.3-70-g09d2