From f07814dd92ebcf4e2c3df5ea01006c0d6c19e29a Mon Sep 17 00:00:00 2001 From: Nilin Reza Date: Mon, 20 Nov 2023 02:10:05 -0500 Subject: [PATCH] feat: implement recipe search - Add recipe-list and recipe-search components - Replace home component with recipe-search - Add searchRecipes method to recipe service - Add SearchRecipes method to RecipeController gh-16 Co-authored-by: Syed Zaidi <26808641+zaidi-01@users.noreply.github.com> Co-authored-by: Zubair Shibly <88159206+StevieShibly8@users.noreply.github.com> --- client/src/app/app.module.ts | 14 ++++++----- client/src/app/home/home.component.html | 14 ----------- client/src/app/home/home.component.ts | 8 ------- .../src/app/nav-menu/nav-menu.component.html | 11 +++------ client/src/app/nav-menu/nav-menu.component.ts | 12 ++++++++-- .../recipe-list/recipe-list.component.html | 19 +++++++++++++++ .../recipe-list/recipe-list.component.scss | 23 +++++++++++++++++++ .../recipe-list/recipe-list.component.spec.ts | 23 +++++++++++++++++++ .../app/recipe-list/recipe-list.component.ts | 16 +++++++++++++ .../recipe-search.component.html | 21 +++++++++++++++++ .../recipe-search.component.scss | 23 +++++++++++++++++++ .../recipe-search.component.spec.ts} | 14 +++++------ .../recipe-search/recipe-search.component.ts | 22 ++++++++++++++++++ client/src/index.html | 2 +- client/src/services/recipe/recipe.service.ts | 9 ++++++-- server/Controllers/RecipeController.cs | 18 +++++++++++++++ 16 files changed, 200 insertions(+), 49 deletions(-) delete mode 100644 client/src/app/home/home.component.html delete mode 100644 client/src/app/home/home.component.ts create mode 100644 client/src/app/recipe-list/recipe-list.component.html create mode 100644 client/src/app/recipe-list/recipe-list.component.scss create mode 100644 client/src/app/recipe-list/recipe-list.component.spec.ts create mode 100644 client/src/app/recipe-list/recipe-list.component.ts create mode 100644 client/src/app/recipe-search/recipe-search.component.html create mode 100644 client/src/app/recipe-search/recipe-search.component.scss rename client/src/app/{home/home.component.spec.ts => recipe-search/recipe-search.component.spec.ts} (51%) create mode 100644 client/src/app/recipe-search/recipe-search.component.ts diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index bd6ed4e..169ea26 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -7,17 +7,19 @@ import { RouterModule } from '@angular/router'; import { ApiAuthorizationModule } from 'src/api-authorization/api-authorization.module'; import { AuthorizeInterceptor } from 'src/api-authorization/authorize.interceptor'; import { AppComponent } from './app.component'; -import { FridgeComponent } from './fridge/fridge.component'; -import { HomeComponent } from './home/home.component'; +import { RecipeSearchComponent } from './recipe-search/recipe-search.component'; import { NavMenuComponent } from './nav-menu/nav-menu.component'; import { RecipeComponent } from './recipe/recipe.component'; +import { FridgeComponent } from './fridge/fridge.component'; +import { RecipeListComponent } from './recipe-list/recipe-list.component'; @NgModule({ declarations: [ AppComponent, NavMenuComponent, - HomeComponent, FridgeComponent, + RecipeListComponent, + RecipeSearchComponent, RecipeComponent, ], imports: [ @@ -30,10 +32,10 @@ import { RecipeComponent } from './recipe/recipe.component'; UpperCasePipe, ApiAuthorizationModule, RouterModule.forRoot([ - { path: '', component: HomeComponent, pathMatch: 'full' }, + { path: '', component: RecipeSearchComponent, pathMatch: 'full' }, { path: 'fridge', component: FridgeComponent }, - { path: 'recipe', component: RecipeComponent }, - ]), + { path: 'recipe', component: RecipeComponent}, + ]) ], providers: [ { provide: HTTP_INTERCEPTORS, useClass: AuthorizeInterceptor, multi: true }, diff --git a/client/src/app/home/home.component.html b/client/src/app/home/home.component.html deleted file mode 100644 index f74c2e7..0000000 --- a/client/src/app/home/home.component.html +++ /dev/null @@ -1,14 +0,0 @@ -

Hello, world!

-

Welcome to your new single-page application, built with:

- -

To help you get started, we've also set up:

- -

The ClientApp subdirectory is a standard Angular CLI application. If you open a command prompt in that directory, you can run any ng command (e.g., ng test), or use npm to install extra packages into it.

diff --git a/client/src/app/home/home.component.ts b/client/src/app/home/home.component.ts deleted file mode 100644 index 2747b30..0000000 --- a/client/src/app/home/home.component.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'app-home', - templateUrl: './home.component.html', -}) -export class HomeComponent { -} diff --git a/client/src/app/nav-menu/nav-menu.component.html b/client/src/app/nav-menu/nav-menu.component.html index b3910ea..b6fc090 100644 --- a/client/src/app/nav-menu/nav-menu.component.html +++ b/client/src/app/nav-menu/nav-menu.component.html @@ -3,7 +3,9 @@ class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3" >
- server + PantryPal + + + diff --git a/client/src/app/recipe-search/recipe-search.component.scss b/client/src/app/recipe-search/recipe-search.component.scss new file mode 100644 index 0000000..921ca2c --- /dev/null +++ b/client/src/app/recipe-search/recipe-search.component.scss @@ -0,0 +1,23 @@ +.center-container { + display: flex; + align-items: center; + height: 10vh; /* This will take the full height of the viewport */ +} + +.form-control { + border-radius: 25px; /* Rounded edges */ + box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); /* Shadow effect */ + padding-left: 35px; /* Make room for the search icon */ + width: 50vw; /* Increase the width of the search bar to 70% of the viewport width */ +} +.form-outline { + position: relative; /* Allow the search icon and filter button to be positioned relative to this element */ + margin-top: 10px; + margin-bottom: 10px; /* Add space after the search bar */ +} +.form-outline i { + position: absolute; + left: 10px; + top: 50%; + transform: translateY(-50%); /* Vertically center the search icon */ +} diff --git a/client/src/app/home/home.component.spec.ts b/client/src/app/recipe-search/recipe-search.component.spec.ts similarity index 51% rename from client/src/app/home/home.component.spec.ts rename to client/src/app/recipe-search/recipe-search.component.spec.ts index 696215b..80dcc8d 100644 --- a/client/src/app/home/home.component.spec.ts +++ b/client/src/app/recipe-search/recipe-search.component.spec.ts @@ -1,18 +1,16 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { HomeComponent } from './home.component'; +import { RecipeSearchComponent } from './recipe-search.component'; -describe('HomeComponent', () => { - let component: HomeComponent; - let fixture: ComponentFixture; +describe('RecipeSearchComponent', () => { + let component: RecipeSearchComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [HomeComponent], + imports: [RecipeSearchComponent], }).compileComponents(); - }); - beforeEach(() => { - fixture = TestBed.createComponent(HomeComponent); + fixture = TestBed.createComponent(RecipeSearchComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/client/src/app/recipe-search/recipe-search.component.ts b/client/src/app/recipe-search/recipe-search.component.ts new file mode 100644 index 0000000..33ba2b5 --- /dev/null +++ b/client/src/app/recipe-search/recipe-search.component.ts @@ -0,0 +1,22 @@ +import { Component } from '@angular/core'; +import { Recipe, RecipeService } from '@services'; + +@Component({ + selector: 'app-search', + templateUrl: './recipe-search.component.html', + styleUrls: ['./recipe-search.component.scss'], +}) +export class RecipeSearchComponent { + public searchText = ''; + public inputText = ''; + public recipeList: Recipe[] = []; + + constructor(private recipeService: RecipeService) {} + + public onSearch(searchQuery: string) { + this.searchText = searchQuery; + this.recipeService + .searchRecipes(searchQuery) + .subscribe((recipeList: Recipe[]) => (this.recipeList = recipeList)); + } +} diff --git a/client/src/index.html b/client/src/index.html index f628984..30b90e8 100644 --- a/client/src/index.html +++ b/client/src/index.html @@ -2,7 +2,7 @@ - server + PantryPal diff --git a/client/src/services/recipe/recipe.service.ts b/client/src/services/recipe/recipe.service.ts index 3fbf125..83c6ae1 100644 --- a/client/src/services/recipe/recipe.service.ts +++ b/client/src/services/recipe/recipe.service.ts @@ -1,7 +1,6 @@ import { HttpClientService } from './../http-client/http-client.service'; import { Injectable } from '@angular/core'; -import { Observable } from 'rxjs'; - +import { Observable, tap, BehaviorSubject } from 'rxjs'; export interface Recipe { id: number; name: string; @@ -28,4 +27,10 @@ export class RecipeService { public getRecipe(id: number): Observable { return this.httpClientService.get(`recipe/${id}`); } + + public searchRecipes(searchQuery: string): Observable { + return this.httpClientService.post('recipe/search', { + searchQuery, + }); + } } diff --git a/server/Controllers/RecipeController.cs b/server/Controllers/RecipeController.cs index 41e2e2d..65fd6ce 100644 --- a/server/Controllers/RecipeController.cs +++ b/server/Controllers/RecipeController.cs @@ -1,9 +1,16 @@ using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using server.Data; +using server.Models; namespace server.Controllers { + public class SearchModel + { + public string SearchQuery { get; set; } + } + + [ApiController] [Route("api/[controller]")] public class RecipeController : ControllerBase @@ -31,5 +38,16 @@ public async Task GetDetails(int id) return NotFound(); } } + + [HttpPost] + [Route("search")] + public async Task SearchRecipes([FromBody] SearchModel searchModel) + { + var recipes = await _context.Recipe + .Where(r => r.Name.ToLower().Contains(searchModel.SearchQuery.ToLower())) + .ToListAsync(); + + return Ok(recipes); + } } } \ No newline at end of file