diff options
Diffstat (limited to 'public/projects/angular-small-apps/apps/recipes/src/app/shared')
14 files changed, 351 insertions, 0 deletions
diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.spec.ts new file mode 100644 index 0000000..6f3c1e4 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.spec.ts @@ -0,0 +1,8 @@ +import { TextareaDirective } from './textarea.directive'; + +describe('TextareaDirective', () => { + it('should create an instance', () => { + const directive = new TextareaDirective(); + expect(directive).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.ts new file mode 100644 index 0000000..dbb1dc0 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/directives/textarea.directive.ts @@ -0,0 +1,49 @@ +import { + AfterViewInit, + Directive, + ElementRef, + HostListener, + Renderer2, +} from '@angular/core'; + +@Directive({ + selector: '[textareaResize]', +}) +export class TextareaDirective implements AfterViewInit { + textareaHeight: string = ''; + + constructor(public renderer: Renderer2, public element: ElementRef) {} + + ngAfterViewInit() { + this.resize(); + this.setTextareaHeight(); + } + + @HostListener('keyup', ['$event']) onKeyDown(e: KeyboardEvent) { + const isCut = e.ctrlKey && e.key === 'x'; + const isDelete = e.key === 'Delete'; + if (isCut || isDelete) { + this.resize('auto'); + } else { + this.resize(); + } + this.setTextareaHeight(); + } + + setTextareaHeight() { + this.renderer.setStyle( + this.element.nativeElement, + 'height', + this.textareaHeight + ); + } + + resize(initialHeight: any = null) { + const textarea = this.element.nativeElement; + this.textareaHeight = initialHeight ?? textarea.height; + + if (textarea.scrollHeight > textarea.clientHeight) { + this.textareaHeight = `${textarea.scrollHeight}px`; + } + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.spec.ts new file mode 100644 index 0000000..e8f923d --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.spec.ts @@ -0,0 +1,8 @@ +import { FormatCommaPipe } from './format-comma.pipe'; + +describe('FormatCommaPipe', () => { + it('create an instance', () => { + const pipe = new FormatCommaPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.ts new file mode 100644 index 0000000..761ae16 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/format-comma.pipe.ts @@ -0,0 +1,18 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +/* + * Add a space after a comma. + * Usage: + * text | formatComma + * Example: + * {{ foo,bar,baz | formatComma }} + * formats to: foo, bar, baz + */ +@Pipe({ + name: 'formatComma', +}) +export class FormatCommaPipe implements PipeTransform { + transform(text: string): string { + return text.replace(/,/g, ', '); + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.spec.ts new file mode 100644 index 0000000..2048bc8 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.spec.ts @@ -0,0 +1,8 @@ +import { SlugifyPipe } from './slugify.pipe'; + +describe('SlugifyPipe', () => { + it('create an instance', () => { + const pipe = new SlugifyPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.ts new file mode 100644 index 0000000..1f44a03 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/pipes/slugify.pipe.ts @@ -0,0 +1,19 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'slugify', +}) +export class SlugifyPipe implements PipeTransform { + transform(text: string): string { + return text + .toString() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() + .trim() + .replace(/\s+/g, '-') + .replace(/[^\w-]+/g, '-') + .replace(/--+/g, '-') + .replace(/^-|-$/g, ''); + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/recipes.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/recipes.ts new file mode 100644 index 0000000..c2fed84 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/recipes.ts @@ -0,0 +1,49 @@ +export interface Recipes { + idMeal: number; + strMeal: string; + strCategory: string; + strInstructions: string; + strMealThumb: string; + strTags: string; + strIngredient1: string; + strIngredient2: string; + strIngredient3: string; + strIngredient4: string; + strIngredient5: string; + strIngredient6: string; + strIngredient7: string; + strIngredient8: string; + strIngredient9: string; + strIngredient10: string; + strIngredient11: string; + strIngredient12: string; + strIngredient13: string; + strIngredient14: string; + strIngredient15: string; + strIngredient16: string; + strIngredient17: string; + strIngredient18: string; + strIngredient19: string; + strIngredient20: string; + strMeasure1: string; + strMeasure2: string; + strMeasure3: string; + strMeasure4: string; + strMeasure5: string; + strMeasure6: string; + strMeasure7: string; + strMeasure8: string; + strMeasure9: string; + strMeasure10: string; + strMeasure11: string; + strMeasure12: string; + strMeasure13: string; + strMeasure14: string; + strMeasure15: string; + strMeasure16: string; + strMeasure17: string; + strMeasure18: string; + strMeasure19: string; + strMeasure20: string; + slug: string; +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.spec.ts new file mode 100644 index 0000000..ba1dbd4 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { LocalStorageService } from './local-storage.service'; + +describe('LocalStorageService', () => { + let service: LocalStorageService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(LocalStorageService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.ts new file mode 100644 index 0000000..82a72e7 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/local-storage.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root', +}) +export class LocalStorageService { + constructor() {} + + get(key: string): any { + try { + const serialItem = localStorage.getItem(key); + if (serialItem) { + return JSON.parse(serialItem); + } else { + return undefined; + } + } catch (e) { + console.log(e); + return undefined; + } + } + + set(key: string, value: any) { + try { + const serialItem = JSON.stringify(value); + localStorage.setItem(key, serialItem); + } catch (e) { + console.log(e); + } + } + + remove(key: string) { + localStorage.removeItem(key); + } + + clear() { + localStorage.clear; + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.spec.ts new file mode 100644 index 0000000..e433b4e --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { RecipesService } from './recipes.service'; + +describe('RecipesService', () => { + let service: RecipesService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(RecipesService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.ts new file mode 100644 index 0000000..a82e019 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/recipes.service.ts @@ -0,0 +1,46 @@ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { Recipes } from '../recipes'; + +@Injectable({ + providedIn: 'root', +}) +export class RecipesService { + private allRecipesAPI = + 'https://www.themealdb.com/api/json/v1/1/search.php?f=a'; + private recipeByIdAPI = + 'https://www.themealdb.com/api/json/v1/1/lookup.php?i='; + private recipeByNameAPI = + 'https://www.themealdb.com/api/json/v1/1/search.php?s='; + private recipeByIngredientAPI = + 'https://www.themealdb.com/api/json/v1/1/filter.php?i='; + private recipeByCategoryAPI = + 'https://www.themealdb.com/api/json/v1/1/filter.php?c='; + + httpOptions = { + headers: new HttpHeaders({ 'Content-Type': 'application/json' }), + }; + + constructor(private http: HttpClient) {} + + getAllRecipes(): Observable<Recipes[]> { + return this.http.get<Recipes[]>(this.allRecipesAPI); + } + + getRecipeById(id: number): Observable<Recipes[]> { + return this.http.get<Recipes[]>(this.recipeByIdAPI + id); + } + + getRecipeByName(name: string): Observable<Recipes[]> { + return this.http.get<Recipes[]>(this.recipeByNameAPI + name); + } + + getRecipeByIngredient(ingredient: string): Observable<Recipes[]> { + return this.http.get<Recipes[]>(this.recipeByIngredientAPI + ingredient); + } + + getRecipeByCategory(category: string): Observable<Recipes[]> { + return this.http.get<Recipes[]>(this.recipeByCategoryAPI + category); + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.spec.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.spec.ts new file mode 100644 index 0000000..23c42c7 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import { SearchService } from './search.service'; + +describe('SearchService', () => { + let service: SearchService; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(SearchService); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.ts new file mode 100644 index 0000000..6c16efd --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/services/search.service.ts @@ -0,0 +1,39 @@ +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; +import { Recipes } from '../recipes'; +import { RecipesService } from './recipes.service'; + +@Injectable({ + providedIn: 'root', +}) +export class SearchService { + private results = new BehaviorSubject<Recipes[]>([]); + + constructor(private recipes: RecipesService) {} + + getResults() { + return this.results.asObservable(); + } + + findResults(query: string, by: string) { + switch (by) { + case 'name': + this.recipes + .getRecipeByName(query) + .subscribe((recipes: any) => this.results.next(recipes.meals)); + break; + case 'ingredient': + this.recipes + .getRecipeByIngredient(query) + .subscribe((recipes: any) => this.results.next(recipes.meals)); + break; + case 'category': + this.recipes + .getRecipeByCategory(query) + .subscribe((recipes: any) => this.results.next(recipes.meals)); + break; + default: + break; + } + } +} diff --git a/public/projects/angular-small-apps/apps/recipes/src/app/shared/utilities/slugify.ts b/public/projects/angular-small-apps/apps/recipes/src/app/shared/utilities/slugify.ts new file mode 100644 index 0000000..15de941 --- /dev/null +++ b/public/projects/angular-small-apps/apps/recipes/src/app/shared/utilities/slugify.ts @@ -0,0 +1,20 @@ +/** + * Convert a text into a slug or id. + * https://gist.github.com/codeguy/6684588#gistcomment-3332719 + * + * @param {string} text Text to slugify. + */ +const slugify = (text: string) => { + return text + .toString() + .normalize('NFD') + .replace(/[\u0300-\u036f]/g, '') + .toLowerCase() + .trim() + .replace(/\s+/g, '-') + .replace(/[^\w-]+/g, '-') + .replace(/--+/g, '-') + .replace(/^-|-$/g, ''); +}; + +export { slugify }; |
