diff options
25 files changed, 717 insertions, 143 deletions
diff --git a/backend/readme.adoc b/backend/readme.adoc index 0dec0b2..bc3c50f 100644 --- a/backend/readme.adoc +++ b/backend/readme.adoc @@ -1,7 +1,7 @@ Backend API =========== Tucker Evans -v1.0, November 22, 2019 +v1.1, December 9, 2019 This REST API allows you to access recipe information in our database with simple HTTP requests. There is currently no authentication/authorization of @@ -16,41 +16,40 @@ The current implementation expects (and returns) recipes in the form: [source,json] ---- { - "Id": 0, - "Title": "Recipe Title", - "Desc": "Recipe Description", - "Photos": [ + "id": 0, + "name": "Recipe name", + "description": "Recipe Description", + "photos": [ "photo_url_1", "photo_url_2" ], - "Serving_size": 0, - "Cook_time": 0, - "Rating": 0, - "Num_cooked": 0, - "Keywords": [ + "servingSize": 0, + "cookTime": 0, + "rating": 0, + "timesCooked": 0, + "tags": [ "keyword 1", "keyword 2", "keyword 3" ], - "Ingredients": [ + "ingredients": [ { - "Name": "Ingredient 1 Name", - "Amount": 1.0, - "Unit": "Ingredient Units" + "name": "Ingredient 1 Name", + "amount": 1.0, + "unit": "Ingredient Units" }, ], - "Steps": [ + "steps": [ { - "Num": 0, - "Desc": "Step Instructions/Description", - "Time": 0 + "instruction": "Step Instructions/Description", + "timer": 0 } ] } ---- [NOTE] -`"Id"` is not required for a POST request, and will be ignored. +`"id"` is not required for a POST request, and will be ignored. [IMPORTANT] Keywords and Photo URLs are currently stored as pipe separated values, the @@ -110,23 +109,23 @@ recipe object in JSON form: ---- $ curl -X POST api.recipebuddy.xyz:8888/recipes -d ' { - "Title":"Test Recipe 2", - "Desc":"This is a descripiton for the test recipe", - "Photos":["photo_url_1","photo_url_2"], - "Serving_size":0, - "Cook_time":60, - "Rating":5, - "Keywords":["keyword_1", "keyword_2","keyword_3"], - "Ingredients":[ - {"Name":"INGR 1","Amount":2.5,"Unit":"cups"}, - {"Name":"INGR 2","Amount":1,"Unit":"oz"} + "name":"Test Recipe 2", + "description":"This is a descripiton for the test recipe", + "photos":["photo_url_1","photo_url_2"], + "servingSize":0, + "cookTime":60, + "rating":5, + "tags":["keyword_1", "keyword_2","keyword_3"], + "ingredients":[ + {"name":"INGR 1","amount":2.5,"unit":"cups"}, + {"name":"INGR 2","amount":1,"unit":"oz"} ], - "Steps":[ - {"Num":1,"Desc":"Step 1: Do this first","Time":10} + "steps":[ + {"instruction":"Step 1: Do this first","timer":10} ] }' -{"Status":{"Code":201,"Msg":"Recipe added successfully"},"Data":{"Id":2,"Title":"Test Recipe 2","Desc":"This is a descripiton for the test recipe","Photos":["photo_url_1","photo_url_2"],"Serving_size":0,"Cook_time":60,"Rating":5,"Num_cooked":0,"Keywords":["keyword_1","keyword_2","keyword_3"],"Ingredients":[{"Name":"INGR 1","Amount":2.5,"Unit":"cups"},{"Name":"INGR 2","Amount":1,"Unit":"oz"}],"Steps":[{"Num":1,"Desc":"Step 1: Do this first","Time":10}]}} +{"Status":{"Code":201,"Msg":"Recipe added successfully"},"Data":{"id":2,"name":"Test Recipe 2","description":"This is a descripiton for the test recipe","photos":["photo_url_1","photo_url_2"],"servingSize":0,"cookTime":60,"rating":5,"timesCooked":0,"tags":["keyword_1","keyword_2","keyword_3"],"ingredients":[{"name":"INGR 1","amount":2.5,"unit":"cups"},{"name":"INGR 2","amount":1,"unit":"oz"}],"steps":[{"instruction":"Step 1: Do this first","timer":10}]}} ---- Read @@ -138,7 +137,7 @@ http://api.recipebuddy.xyz:8888/recipes/0[`/recipes/{id}`], the HTTP body is ign ---- $ curl -X GET api.recipebuddy.xyz:8888/recipes/1 -{"Status":{"Code":200,"Msg":"Successful"},"Data":{"Id":1,"Title":"Test Recipe","Desc":"This is a descripiton for the test recipe","Photos":["photo_url_1","photo_url_2",""],"Serving_size":0,"Cook_time":60,"Rating":5,"Num_cooked":0,"Keywords":["keyword_1","keyword_2","keyword_3",""],"Ingredients":[{"Name":"INGR 1","Amount":2.5,"Unit":"cups"},{"Name":"INGR 2","Amount":1,"Unit":"oz"}],"Steps":[{"Num":1,"Desc":"Step 1: Do this first","Time":10}]}} +{"Status":{"Code":200,"Msg":"Successful"},"Data":{"id":1,"name":"Test Recipe","description":"This is a descripiton for the test recipe","photos":["photo_url_1","photo_url_2",""],"servingSize":0,"cookTime":60,"rating":5,"timesCooked":0,"tags":["keyword_1","keyword_2","keyword_3",""],"ingredients":[{"name":"INGR 1","amount":2.5,"unit":"cups"},{"name":"INGR 2","amount":1,"unit":"oz"}],"steps":[{"instruction":"Step 1: Do this first","timer":10}]}} ---- To access a list of all recipe ids in the database send a `GET` request to @@ -158,24 +157,24 @@ complete recipe in JSON form. ---- $ curl -X PUT localhost:8888/recipes/1 -d ' { - "Id": 1, - "Title":"Test Recipe 1", - "Desc":"This is a descripiton for the test recipe", - "Photos":[ "photo_url_1", "photo_url_2" ], - "Serving_size":0, - "Cook_time":60, - "Rating":5, - "Keywords":[ "keyword_1", "keyword_2", "keyword_3" ], - "Ingredients":[ - { "Name":"INGR 1", "Amount":2.5, "Unit":"cups" }, - { "Name":"INGR 2", "Amount":1, "Unit":"oz" } + "id": 1, + "name":"Test Recipe 1", + "description":"This is a descripiton for the test recipe", + "photos":[ "photo_url_1", "photo_url_2" ], + "servingSize":0, + "cookTime":60, + "rating":5, + "tags":[ "keyword_1", "keyword_2", "keyword_3" ], + "ingredients":[ + { "name":"INGR 1", "amount":2.5, "unit":"cups" }, + { "name":"INGR 2", "amount":1, "unit":"oz" } ], - "Steps":[ - { "Num":0, "Desc":"Step 1: Do this first", "Time":10 } + "steps":[ + { "instruction":"Step 1: Do this first", "timer":10 } ] }' -{"Status":{"Code":201,"Msg":"Recipe added successfully"},"Data":{"Id":1,"Title":"Test Recipe 1","Desc":"This is a descripiton for the test recipe","Photos":["photo_url_1","photo_url_2"],"Serving_size":0,"Cook_time":60,"Rating":5,"Num_cooked":0,"Keywords":["keyword_1","keyword_2","keyword_3"],"Ingredients":[{"Name":"INGR 1","Amount":2.5,"Unit":"cups"},{"Name":"INGR 2","Amount":1,"Unit":"oz"}],"Steps":[{"Num":0,"Desc":"Step 1: Do this first","Time":10}]}} +{"Status":{"Code":201,"Msg":"Recipe added successfully"},"Data":{"id":1,"name":"Test Recipe 1","description":"This is a descripiton for the test recipe","photos":["photo_url_1","photo_url_2"],"servingSize":0,"cookTime":60,"rating":5,"timesCooked":0,"tags":["keyword_1","keyword_2","keyword_3"],"ingredients":[{"name":"INGR 1","amount":2.5,"unit":"cups"},{"name":"INGR 2","amount":1,"unit":"oz"}],"steps":[{"instruction":"Step 1: Do this first","timer":10}]}} ---- [WARNING] diff --git a/backend/recipe.go b/backend/recipe.go index a3191c3..59b7366 100644 --- a/backend/recipe.go +++ b/backend/recipe.go @@ -6,12 +6,11 @@ import "strings" type Ingredient struct { Name string `json:"name"` Amount float64 `json:"amount"` - Unit string `json:"units"` - Type string `json:"type"` + Unit string `json:"unit"` } type Step struct { - Desc string `json:"instructions"` + Desc string `json:"instruction"` Time int `json:"timer"` } diff --git a/recipeBuddy/src/app/DataModels/ingredient.ts b/recipeBuddy/src/app/DataModels/ingredient.ts index c79b475..720514c 100644 --- a/recipeBuddy/src/app/DataModels/ingredient.ts +++ b/recipeBuddy/src/app/DataModels/ingredient.ts @@ -1,8 +1,8 @@ export class Ingredient { - private name: string; - private amount: number; - private unit: string; - private type_: string; + public name: string; + public amount: number; + public unit: string; + public type_: string; public constructor(name: string, amount: number, unit: string, type_: string) { this.name = name; diff --git a/recipeBuddy/src/app/DataModels/recipe.ts b/recipeBuddy/src/app/DataModels/recipe.ts index 937153f..18c4716 100644 --- a/recipeBuddy/src/app/DataModels/recipe.ts +++ b/recipeBuddy/src/app/DataModels/recipe.ts @@ -2,17 +2,17 @@ import {Step} from "./step" import {Ingredient} from "./ingredient" export class Recipe { - private id: number; - private name: string; - private description: string; - private ingredients: Ingredient[]; - private steps: Step[]; - private servingSize: number; - private cookTime: number; - private timesCooked: number; - private rating: number; - private tags: string[]; - private photos: string[]; + public id: number; + public name: string; + public description: string; + public ingredients: Ingredient[]; + public steps: Step[]; + public servingSize: number; + public cookTime: number; + public timesCooked: number; + public rating: number; + public tags: string[]; + public photos: string[]; public constructor(id: number, name: string, diff --git a/recipeBuddy/src/app/DataModels/step.ts b/recipeBuddy/src/app/DataModels/step.ts index 67e14c1..ec33e15 100644 --- a/recipeBuddy/src/app/DataModels/step.ts +++ b/recipeBuddy/src/app/DataModels/step.ts @@ -1,13 +1,13 @@ export class Step { - private instruction: string; - private timer: number; + public instruction: string; + public timer: number; public constructor(instruction: string, timer: number) { this.instruction = instruction; this.timer = timer; } - public getInstruction(): string { + public getInstructions(): string { return this.instruction; } diff --git a/recipeBuddy/src/app/add-recipe/add-recipe.component.ts b/recipeBuddy/src/app/add-recipe/add-recipe.component.ts index 407997c..5109c34 100644 --- a/recipeBuddy/src/app/add-recipe/add-recipe.component.ts +++ b/recipeBuddy/src/app/add-recipe/add-recipe.component.ts @@ -7,6 +7,8 @@ import { FormArray } from '@angular/forms'; import { Validators } from '@angular/forms'; +import { Router } from '@angular/router'; + import { Recipe } from '../DataModels/recipe'; import { Ingredient } from '../DataModels/ingredient' import { Step } from '../DataModels/step'; @@ -43,7 +45,8 @@ export class AddRecipeComponent { }); constructor(private fb: FormBuilder, - private restService: BackendService + private restService: BackendService, + private router: Router, ) { } ngOnInit() { @@ -99,9 +102,9 @@ export class AddRecipeComponent { } var steps = [] - for (i = 0; i < formData.ingredients.length; i++) { - var tmp_timer = parseInt(formData.steps[0].timer) - steps.push(new Step(formData.steps[0].instruct, + for (i = 0; i < formData.steps.length; i++) { + var tmp_timer = parseInt(formData.steps[i].timer) + steps.push(new Step(formData.steps[i].instruct, (isNaN(tmp_timer) ? 0 : tmp_timer) )); } @@ -118,9 +121,10 @@ export class AddRecipeComponent { (isNaN(cookTimeTmp) ? 0 :cookTimeTmp), //cookTime 0, //timesCooked 0, //rating - formData.tags.split(','), //tags - formData.photos.split(',') //photos + formData.tags.split(',').filter(word=> !(word==="")), //tags + formData.photos.split(',').filter(word=> !(word==="")) //photos ); - this.restService.createRecipe(recipe).subscribe() + this.restService.createRecipe(recipe).subscribe(); + this.router.navigate(['/']); } } diff --git a/recipeBuddy/src/app/app-routing.module.ts b/recipeBuddy/src/app/app-routing.module.ts index bb7c96e..0084f01 100644 --- a/recipeBuddy/src/app/app-routing.module.ts +++ b/recipeBuddy/src/app/app-routing.module.ts @@ -2,12 +2,16 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; import { CookPageComponent } from './cook-page/cook-page.component'; +import { PreCookPopUpComponent } from './pre-cook-pop-up/pre-cook-pop-up.component'; import { AddRecipeComponent } from './add-recipe/add-recipe.component'; +import { EditRecipeComponent } from './edit-recipe/edit-recipe.component'; const routes: Routes = [ { path: '', redirectTo: '/cook', pathMatch: 'full' }, + { path: 'preCook' , component: PreCookPopUpComponent }, + { path: 'add', component: AddRecipeComponent }, { path: 'cook', component: CookPageComponent }, - { path: 'add', component: AddRecipeComponent } + { path: 'edit', component: EditRecipeComponent }, ]; @NgModule({ diff --git a/recipeBuddy/src/app/app.component.html b/recipeBuddy/src/app/app.component.html index 014c6b0..830c5cb 100644 --- a/recipeBuddy/src/app/app.component.html +++ b/recipeBuddy/src/app/app.component.html @@ -1,2 +1,18 @@ -<h1>{{title}}</h1> +<mat-toolbar color="primary"> + <span style="margin-left: 15px"> + <button mat-button routerLink="/" routerLinkActive="active"><h1>{{title}}</h1></button> + </span> + <span style="flex: 1 1 auto"></span> + <div style="margin-right: 15px"> + <button mat-icon-button routerLink="/add" routerLinkActive="active"> + <mat-icon style="padding-left: 8px; padding-right: 8px">add</mat-icon> + </button> + <button mat-icon-button routerLink="/cart" routerLinkActive="active"> + <mat-icon style="padding-left: 8px; padding-right: 8px">shopping_cart</mat-icon> + </button> + <button mat-icon-button routerLink="/search" routerLinkActive="active"> + <mat-icon style="padding-left: 8px; padding-right: 8px">search</mat-icon> + </button> + </div> +</mat-toolbar> <router-outlet></router-outlet> diff --git a/recipeBuddy/src/app/app.module.ts b/recipeBuddy/src/app/app.module.ts index 359254e..c2bdc68 100644 --- a/recipeBuddy/src/app/app.module.ts +++ b/recipeBuddy/src/app/app.module.ts @@ -2,14 +2,16 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { MatCardModule } from '@angular/material'; +import { MatDialogModule } from '@angular/material'; import { AppComponent } from './app.component'; import { CookPageComponent} from './cook-page/cook-page.component'; -import { StepCardComponent } from './cook-page/step-card/step-card.component'; +//import { RecipePassService } from './recipePass/recipe-pass.service'; import { AppRoutingModule } from './app-routing.module'; import { HttpClientModule } from '@angular/common/http'; +import { PreCookPopUpComponent } from './pre-cook-pop-up/pre-cook-pop-up.component'; import { AddRecipeComponent } from './add-recipe/add-recipe.component'; import { ReactiveFormsModule } from '@angular/forms'; @@ -19,13 +21,16 @@ import { MatInputModule } from '@angular/material/input'; import { MatFormFieldModule } from '@angular/material'; import { MatIconModule } from '@angular/material/icon'; import { MatButtonModule } from '@angular/material/button'; +import { MatToolbarModule } from '@angular/material/toolbar'; +import { EditRecipeComponent } from './edit-recipe/edit-recipe.component'; @NgModule({ declarations: [ AppComponent, CookPageComponent, - StepCardComponent, - AddRecipeComponent + PreCookPopUpComponent, + AddRecipeComponent, + EditRecipeComponent, ], imports: [ BrowserModule, @@ -37,9 +42,10 @@ import { MatButtonModule } from '@angular/material/button'; MatInputModule, MatFormFieldModule, MatIconModule, - MatButtonModule + MatButtonModule, + MatToolbarModule, ], - providers: [], - bootstrap: [AppComponent] + bootstrap: [AppComponent], +// providers: [RecipePassService] }) export class AppModule { } diff --git a/recipeBuddy/src/app/cook-page/cook-page.component.css b/recipeBuddy/src/app/cook-page/cook-page.component.css index 41b3d42..b2b97e5 100644 --- a/recipeBuddy/src/app/cook-page/cook-page.component.css +++ b/recipeBuddy/src/app/cook-page/cook-page.component.css @@ -1,33 +1,35 @@ -.previous-step { - -} - -.current-step { - -} - -.next-step { -} - .previous { margin: auto; + width: 200px; + height: 200px; border: solid; + align: center; text-align: center; grid-column: 1; + background-color: grey; + + } .current { margin: auto; + width: 300px; + height:300px; border: solid; text-align: center; grid-column: 2; + background-color: grey; } .next { margin: auto; + width: 200px; + height: 200px; border: solid; + align: center; text-align: center; grid-column: 3; + background-color: grey; } @@ -37,3 +39,7 @@ grid-gap: 10px; grid-template-rows: 1fr; } + +.step-count { + text-align: center; +} diff --git a/recipeBuddy/src/app/cook-page/cook-page.component.html b/recipeBuddy/src/app/cook-page/cook-page.component.html index 39bef2e..4744ed1 100644 --- a/recipeBuddy/src/app/cook-page/cook-page.component.html +++ b/recipeBuddy/src/app/cook-page/cook-page.component.html @@ -1,22 +1,28 @@ <div class="container"> - <div class="previous"> - <h1>Step {{step -1}}</h1> + Serving {{servingSize}} + <div class="previous" *ngIf="!firstStep"> + <h1>Step {{stepNum -1}}</h1> <p>{{previousStep}}</p> </div> <div class="current"> - <h1>Step {{step}}</h1> + <h1>Step {{stepNum}}</h1> <p>{{currentStep}}</p> - <p>{{timeLeft}}</p> - <div> + <div *ngIf="hasTimer()"> + +<h4>{{timeHoursFirst}}{{timeHoursSecond}}:{{timeMinutesFirst}}{{timeMinutesSecond}}:{{timeSecondsFirst}}{{timeSecondsSecond}}</h4> <button (click)="startTimer()">Start Timer</button> </div> - <button (click)="previous()">Previous</button> - <button (click)="next()">next</button> + <button *ngIf="!firstStep" (click)="previous()">Previous</button> + <button *ngIf="!lastStep" (click)="next()">next</button> </div> - <div class="next"> - <h1>Step {{step +1}}</h1> + <div class="next" *ngIf="!lastStep"> + <h1>Step {{stepNum +1}}</h1> <p>{{nextStep}}</p> </div> </div> + +<div class="step-count"> + <h1>Step: {{stepNum}}/{{steps.length}}</h1> +</div> diff --git a/recipeBuddy/src/app/cook-page/cook-page.component.ts b/recipeBuddy/src/app/cook-page/cook-page.component.ts index 51a4c67..a3a1dfe 100644 --- a/recipeBuddy/src/app/cook-page/cook-page.component.ts +++ b/recipeBuddy/src/app/cook-page/cook-page.component.ts @@ -1,54 +1,102 @@ import {Component, OnInit} from '@angular/core'; +import {Recipe} from '../DataModels/recipe'; +import {Step} from '../DataModels/step'; +import {RecipePassService} from '../recipePass/recipe-pass.service' -/** - * @title Card with multiple sections - */ @Component({ selector: 'app-cook-page', templateUrl: './cook-page.component.html', - styleUrls: ['./cook-page.component.css'], + styleUrls: ['./cook-page.component.css'] }) export class CookPageComponent implements OnInit { - step: number; - instructions: string[] = ["Cut the bread", "Toast the bread", "Warm the butter", "Apply butter to bread", "Enjoy"]; - timers: number[] = [5,60,30,0,0]; + steps: Step[]; + stepNum: number; + + firstStep: boolean = true; + lastStep: boolean = false; + servingSize: number; + previousStep: string; currentStep: string; nextStep: string; timeLeft: number; + timeHoursFirst: number; + timeHoursSecond: number; + timeMinutesFirst: number; + timeMinutesSecond: number; + timeSecondsFirst: number; + timeSecondsSecond: number; + timerInterval; + constructor(private recipePass: RecipePassService){} + ngOnInit() { - this.step = 1; - this.previousStep = ""; - this.currentStep = this.instructions[this.step-1]; - this.nextStep = this.instructions[this.step]; - this.timeLeft = this.timers[this.step-1]; + var recipe: Recipe = this.recipePass.getRecipe(); + this.steps = recipe.steps; + this.servingSize = recipe.servingSize; + this.stepNum = 1; + this.currentStep = this.steps[this.stepNum-1].instruction; + if(this.steps.length > 1) + this.nextStep = this.steps[this.stepNum].instruction; + else + this.lastStep = true; + + this.timeLeft = this.steps[this.stepNum-1].timer; + this.timeHoursFirst = Math.floor(this.timeLeft/3600/10); + this.timeHoursSecond = Math.floor(this.timeLeft/3600%10); + this.timeMinutesFirst = Math.floor(this.timeLeft%3600/60/10); + this.timeMinutesSecond = Math.floor(this.timeLeft%3600/60%10); + this.timeSecondsFirst = Math.floor(this.timeLeft%3600%60/10); + this.timeSecondsSecond = Math.floor(this.timeLeft%3600%60%10); } next(): void { + this.firstStep = false; clearInterval(this.timerInterval); - this.step++; - this.previousStep = this.instructions[this.step-2]; - this.currentStep = this.instructions[this.step-1]; - this.nextStep = this.instructions[this.step]; - this.timeLeft = this.timers[this.step-1]; + this.stepNum++; + if(this.stepNum == this.steps.length) { + this.lastStep = true; + } else { + this.nextStep = this.steps[this.stepNum].instruction; + } + this.previousStep = this.steps[this.stepNum-2].instruction; + this.currentStep = this.steps[this.stepNum-1].instruction; + this.timeLeft = this.steps[this.stepNum-1].timer; } previous(): void { + this.lastStep = false; clearInterval(this.timerInterval); - this.step--; - this.previousStep = this.instructions[this.step-2]; - this.currentStep = this.instructions[this.step-1]; - this.nextStep = this.instructions[this.step]; - this.timeLeft = this.timers[this.step-1]; + this.stepNum--; + if(this.stepNum == 1) { + this.firstStep = true; + } else { + this.previousStep = this.steps[this.stepNum-2].instruction; + } + this.currentStep = this.steps[this.stepNum-1].instruction; + this.nextStep = this.steps[this.stepNum].instruction; + this.timeLeft = this.steps[this.stepNum-1].timer; + } + + hasTimer(): boolean { + if(this.steps[this.stepNum-1].timer > 0) + return true; + else + return false; } startTimer(): void { + console.log("timerStarted"); this.timerInterval = setInterval(() => { if(this.timeLeft > 0) { - this.timeLeft --; + this.timeHoursFirst = Math.floor(this.timeLeft/3600/10); + this.timeHoursSecond = Math.floor(this.timeLeft/3600%10); + this.timeMinutesFirst = Math.floor(this.timeLeft%3600/60/10); + this.timeMinutesSecond = Math.floor(this.timeLeft%3600/60%10); + this.timeSecondsFirst = Math.floor(this.timeLeft%3600%60/10); + this.timeSecondsSecond = Math.floor(this.timeLeft%3600%60%10); } else { clearInterval(this.timerInterval); @@ -56,4 +104,3 @@ export class CookPageComponent implements OnInit { }, 1000) } } - diff --git a/recipeBuddy/src/app/cook-page/step-card/step-card.component.css b/recipeBuddy/src/app/cook-page/step-card/step-card.component.css deleted file mode 100644 index e69de29..0000000 --- a/recipeBuddy/src/app/cook-page/step-card/step-card.component.css +++ /dev/null diff --git a/recipeBuddy/src/app/cook-page/step-card/step-card.component.html b/recipeBuddy/src/app/cook-page/step-card/step-card.component.html deleted file mode 100644 index c3edca3..0000000 --- a/recipeBuddy/src/app/cook-page/step-card/step-card.component.html +++ /dev/null @@ -1 +0,0 @@ -<p>step-card works!</p> diff --git a/recipeBuddy/src/app/cook-page/step-card/step-card.component.ts b/recipeBuddy/src/app/cook-page/step-card/step-card.component.ts deleted file mode 100644 index 6d490b7..0000000 --- a/recipeBuddy/src/app/cook-page/step-card/step-card.component.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Component } from '@angular/core'; - -@Component({ - selector: 'step-card', - templateUrl: 'step-card.component.html', - styleUrls: ['step-card.component.css'] -}) -export class StepCardComponent{ -} diff --git a/recipeBuddy/src/app/edit-recipe/edit-recipe.component.css b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.css new file mode 100644 index 0000000..9d74c53 --- /dev/null +++ b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.css @@ -0,0 +1,43 @@ +.form { + min-width: 150px; + max-width: 750px; + width: 95%; + margin-left: auto; + margin-right: auto; + padding-left: 5px; + padding-right: 5px; +} + +.full-width { + width: 100%; +} + +.half-width { + width: 50%; + padding: 1%; + margin-left:auto; + margin-right:auto; +} + +.quarter-width { + width: 25%; + padding: 1%; + margin-left:auto; + margin-right:auto; +} + +.third-width { + width: 33%; + padding: 1%; + margin-left:auto; + margin-right:auto; +} + +td { + padding-right: 8px; +} + +.center { + margin-left:auto; + margin-right:auto; +} diff --git a/recipeBuddy/src/app/edit-recipe/edit-recipe.component.html b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.html new file mode 100644 index 0000000..a8f2e97 --- /dev/null +++ b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.html @@ -0,0 +1,110 @@ +<form [formGroup]="recipeForm" class="form" (ngSubmit)="onSubmit()"> +<h2>Add Recipe</h2> + <mat-form-field class="full-width"> + <input matInput placeholder="Name" type="text" + formControlName="recipeName" required> + <mat-hint> + Name is required + </mat-hint> + <mat-error> + Name is required + </mat-error> + </mat-form-field> + <mat-form-field class="full-width"> + <textarea matInput placeholder="Description" + formControlName="desc"> TEST </textarea> + </mat-form-field> + <mat-form-field class="full-width"> + <input matInput placeholder="Servings" type=text + formControlName="servingSize" pattern="^[0-9]*(\.[0-9]*)?$"> + <mat-error> + Servings must be a number. + </mat-error> + </mat-form-field> + <mat-form-field class="full-width"> + <input matInput placeholder="Cooking Time" type="text" formControlName="cookTime" + pattern="^[0-9]*$"> + <span matSuffix>Minutes</span> + <mat-error> + Must be in the form hh:mm + </mat-error> + </mat-form-field> + <mat-form-field class="full-width" floatLabel="options.value.floatLabel"> + <mat-label>Keywords/Tags</mat-label> + <input matInput placeholder="Separate with a comma" type="text" formControlName="tags"> + </mat-form-field> + <mat-form-field class="full-width" floatLabel="options.value.floatLabel"> + <mat-label>Photos (URLS)</mat-label> + <input matInput placeholder="Separate with a comma" type="text" formControlName="photos"> + </mat-form-field> + + <div formArrayName="ingredients"> + <h3>Ingredients</h3> + <div *ngFor="let ingr of ingredients.controls; let i=index"> + <div [formGroupName]="i"> + <h4>Ingredient {{ i + 1 }}</h4> + <div class="full-width"> + <mat-form-field class="quarter-width"> + <input matInput placeholder="Name" type="text" + formControlName="name"> + </mat-form-field> + <mat-form-field class="quarter-width"> + <input matInput placeholder="Amount" + type="text" + formControlName="amount" pattern="^[0-9]*(\.[0-9]*)?$"> + <mat-error> + Amount must be a number. + </mat-error> + </mat-form-field> + <mat-form-field class="quarter-width"> + <input matInput placeholder="Units" type="text" + formControlName="unit"> + </mat-form-field> + <button matSuffix mat-mini-fab (click)="rmIngredient(i)" + type="button" style="margin-left: 10px"> + <mat-icon>remove</mat-icon> + </button> + </div> + </div> + </div> + <div style="text-align: center"> + <button mat-mini-fab (click)="addIngredient()" + type="button"> + <mat-icon>add</mat-icon> + </button> + </div> + </div> + + <div formArrayName="steps"> + <h3>Steps</h3> + <div *ngFor="let address of steps.controls; let i=index"> + <div [formGroupName]="i"> + <h4>Step {{ i + 1 }}</h4> + <div class="ful-width"> + <mat-form-field class="half-width"> + <textarea matInput placeholder="Instructions" type="text" + formControlName="instruction"> + </textarea> + </mat-form-field> + <mat-form-field class="quarter-width"> + <input matInput placeholder="Timer" type="text" + formControlName="timer" pattern="^[0-9]*$"> + <span matSuffix>Minutes</span> + </mat-form-field> + <button matSuffix mat-mini-fab (click)="rmStep(i)" + type="button" style="margin-left: 10px"> + <mat-icon>remove</mat-icon> + </button> + </div> + </div> + </div> + <div style="text-align: center"> + <button mat-mini-fab (click)="addStep()" matSuffix type="button"> + <mat-icon>add</mat-icon> + </button> + </div> + </div> + <button mat-flat-button color="primary" type="submit" + [disabled]="!recipeForm.valid" style="margin-right: 5px">Update</button> + <button mat-flat-button color="primary" (click)="onCancel()" >Cancel</button> +</form> diff --git a/recipeBuddy/src/app/cook-page/step-card/step-card.component.spec.ts b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.spec.ts index 011bc44..e92d28b 100644 --- a/recipeBuddy/src/app/cook-page/step-card/step-card.component.spec.ts +++ b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.spec.ts @@ -1,20 +1,20 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing'; -import { StepCardComponent } from './step-card.component'; +import { EditRecipeComponent } from './edit-recipe.component'; -describe('StepCardComponent', () => { - let component: StepCardComponent; - let fixture: ComponentFixture<StepCardComponent>; +describe('EditRecipeComponent', () => { + let component: EditRecipeComponent; + let fixture: ComponentFixture<EditRecipeComponent>; beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [ StepCardComponent ] + declarations: [ EditRecipeComponent ] }) .compileComponents(); })); beforeEach(() => { - fixture = TestBed.createComponent(StepCardComponent); + fixture = TestBed.createComponent(EditRecipeComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/recipeBuddy/src/app/edit-recipe/edit-recipe.component.ts b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.ts new file mode 100644 index 0000000..203f733 --- /dev/null +++ b/recipeBuddy/src/app/edit-recipe/edit-recipe.component.ts @@ -0,0 +1,188 @@ +import { Component, OnInit } from '@angular/core'; + +import { FormControl } from '@angular/forms'; + +import { FormBuilder } from '@angular/forms'; +import { FormArray } from '@angular/forms'; + +import { Validators } from '@angular/forms'; + +import { Router } from '@angular/router'; + +import { Recipe } from '../DataModels/recipe'; +import { Ingredient } from '../DataModels/ingredient' +import { Step } from '../DataModels/step'; +import { BackendService } from '../REST_service/backend.service'; + +@Component({ + selector: 'app-edit-recipe', + templateUrl: './edit-recipe.component.html', + styleUrls: ['./edit-recipe.component.css'] +}) +export class EditRecipeComponent implements OnInit { + + baseRecipe: Recipe = new Recipe (15, //id + '', //name + '', //description + [], //ingredients + [], //steps + 0, //servingSize + 0, //cookTime + 0, //timesCooked + 0, //rating + [], //tags + [] //photos + ); + + recipeForm = this.fb.group({ + recipeName: ['', Validators.required], + desc: [''], + ingredients: this.fb.array([ + this.fb.group({ + name: [''], + amount: ['', Validators.pattern('^[0-9]*(\.[0-9]*)?$')], + unit: [''] + }) + ]), + steps: this.fb.array([ + this.fb.group({ + instruction: [''], + timer: [''] + }) + ]), + servingSize: ['', Validators.pattern('^[0-9]*(\.[0-9]*)?$')], + cookTime: ['', Validators.pattern('^[0-9]*$')], + tags: [''], + photos: [''] + }); + + constructor(private fb: FormBuilder, + private restService: BackendService, + private router: Router, + /*private passService: PassService,*/ + ) + { + restService.getRecipe(this.baseRecipe.id).subscribe( + res=> this.updateRecipe(res), + err=> console.log('EditRecipeComponent:restService:getRecipes: id='+ this.baseRecipe.id + 'err=' + err), + () => console.log('EditRecipe:restService:getRecipes: completed') + ) + + this.rmIngredient(0); + this.rmStep(0); + } + + updateRecipe(r: Recipe) + { + var i: number; + + this.recipeForm.patchValue( + { + recipeName: r.name, + desc: r.description, + servingSize: r.servingSize, + cookTime: r.cookTime, + tags: r.tags.join(','), + photos: r.photos.join(','), + } + ) + + console.log(r.tags.join(',')); + + for(i = 0; i < r.ingredients.length; i++) { + this.addIngredient(); + this.ingredients.controls[0].setValue(r.ingredients[i]); + } + for(i = 0; i < r.steps.length; i++) { + this.addStep(); + console.log(r.steps[i]) + this.steps.controls[0].setValue(r.steps[i]); + } + } + + ngOnInit() { + } + + get ingredients() { + return this.recipeForm.get('ingredients') as FormArray; + } + + addIngredient() { + this.ingredients.push( + this.fb.group({ + name: [''], + amount: ['', Validators.pattern('^[0-9]*(\.[0-9]*)?$')], + unit: [''] + }) + ); + } + + rmIngredient(i) { + this.ingredients.removeAt(i); + } + + get steps() { + return this.recipeForm.get('steps') as FormArray; + } + + addStep() { + this.steps.push( + this.fb.group({ + instruction: [''], + timer: ['', Validators.pattern('^[0-9]*$')] + }) + ); + } + + rmStep(i) { + this.steps.removeAt(i); + } + + onSubmit() { + var formData = this.recipeForm.value; + + var ingredients = [] + var i; + for (i = 0; i < formData.ingredients.length; i++) { + var tmp_amount = parseFloat(formData.ingredients[0].amount) + ingredients.push(new Ingredient(formData.ingredients[0].name, + (isNaN(tmp_amount) ? 0 : tmp_amount), + formData.ingredients[0].unit, + "" + )); + } + + var steps = [] + for (i = 0; i < formData.steps.length; i++) { + var tmp_timer = parseInt(formData.steps[0].timer) + steps.push(new Step(formData.steps[0].instruction, + (isNaN(tmp_timer) ? 0 : tmp_timer) + )); + } + + console.log(steps); + + var servingsTmp = parseFloat(formData.servingSize) + var cookTimeTmp = parseInt(formData.cookTime) + + var recipe = new Recipe (this.baseRecipe.id, //id + formData.recipeName, //name + formData.desc, //description + ingredients, //ingredients + steps, //steps + (isNaN(servingsTmp) ? 0 :servingsTmp), //servingSize + (isNaN(cookTimeTmp) ? 0 :cookTimeTmp), //cookTime + 0, //timesCooked + 0, //rating + formData.tags.split(',').filter(word => !(word==="")), //tags + formData.photos.split(',').filter(word => !(word==="")) //photos + ); + console.log(recipe) + this.restService.updateRecipe(recipe).subscribe() + this.router.navigate(['/']); + } + + onCancel() { + this.router.navigate(['/']); + } +} diff --git a/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.css b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.css new file mode 100644 index 0000000..809e58b --- /dev/null +++ b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.css @@ -0,0 +1,37 @@ +h1 {text-align: center} +h4 { text-align: center; + margin-bottom:0px; + } +.outer-box { + display:grid; + width: 400px; + margin: auto; + padding: 10px; + border: solid; + align-content: center; + align-self: center; +} + +.input-box { + text-align:center; + margin: auto; +} + +.ingredients-list { + margin: auto; + padding: 10px; + border: solid; + outline: 0px solid; +} + +.button { + display: block; + margin: 10px auto; +} + +li{text-align: center} +input{display: inline-block; + width: 20px} +button{width: 150px; + height: 50px; + } diff --git a/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.html b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.html new file mode 100644 index 0000000..c1ef1ef --- /dev/null +++ b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.html @@ -0,0 +1,16 @@ +<div *ngIf="cookedRecipe" class="outer-box"> + <h1>{{cookedRecipe.name}}</h1> + + <div class="input-box"> + Serving<input (keyup)="updateRecipe($event)"> + </div> + + <h4>Ingredients:</h4> + <div class="ingredients-list"> + <li *ngFor="let ing of cookedRecipe.ingredients"> + {{ing.name}}, {{ing.amount}} {{ing.unit}} + + </div> +</div> + +<button class="button" routerLink="/cook"> Ready </button> diff --git a/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.spec.ts b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.spec.ts new file mode 100644 index 0000000..b355855 --- /dev/null +++ b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { PreCookPopUpComponent } from './pre-cook-pop-up.component'; + +describe('PreCookPopUpComponent', () => { + let component: PreCookPopUpComponent; + let fixture: ComponentFixture<PreCookPopUpComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ PreCookPopUpComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PreCookPopUpComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.ts b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.ts new file mode 100644 index 0000000..208993f --- /dev/null +++ b/recipeBuddy/src/app/pre-cook-pop-up/pre-cook-pop-up.component.ts @@ -0,0 +1,46 @@ +import { Component, OnInit } from '@angular/core'; +import { RecipePassService } from '../recipePass/recipe-pass.service'; +import { Recipe } from '../DataModels/recipe'; +import { Ingredient } from '../DataModels/ingredient'; +import { BackendService } from '../REST_service/backend.service'; +import { Router } from '@angular/router'; + +@Component({ + selector: 'app-pre-cook-pop-up', + templateUrl: './pre-cook-pop-up.component.html', + styleUrls: ['./pre-cook-pop-up.component.css'] +// providers: [RecipePassService] +}) +export class PreCookPopUpComponent implements OnInit { + + cookedRecipe: Recipe; + newSize: number; + originalAmounts: number[] = []; + originalSize: number; + + constructor(private recipePass: RecipePassService, private backend: BackendService, private router: Router) { } + + ngOnInit() { + this.backend.getRecipe(15).subscribe(res => + { + console.log(res); + this.cookedRecipe = res; + this.originalSize = this.cookedRecipe.servingSize; + for(var _i = 0; _i < this.cookedRecipe.ingredients.length; _i++) { + this.originalAmounts[_i] = this.cookedRecipe.ingredients[_i].amount; + } + }); + } + + updateRecipe(event: any) { + if(event.target.value) { + this.newSize = parseInt(event.target.value); + for(var _i = 0; _i < this.cookedRecipe.ingredients.length; _i++) { + this.cookedRecipe.ingredients[_i].amount = Math.round(this.originalAmounts[_i] * (this.newSize / this.originalSize)); + } + + this.cookedRecipe.servingSize = this.newSize; + this.recipePass.setRecipe(this.cookedRecipe); + } + } +} diff --git a/recipeBuddy/src/app/recipePass/recipe-pass.service.spec.ts b/recipeBuddy/src/app/recipePass/recipe-pass.service.spec.ts new file mode 100644 index 0000000..f3a8388 --- /dev/null +++ b/recipeBuddy/src/app/recipePass/recipe-pass.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { RecipePassService } from './recipe-pass.service'; + +describe('RecipePassService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: RecipePassService = TestBed.get(RecipePassService); + expect(service).toBeTruthy(); + }); +}); diff --git a/recipeBuddy/src/app/recipePass/recipe-pass.service.ts b/recipeBuddy/src/app/recipePass/recipe-pass.service.ts new file mode 100644 index 0000000..e925973 --- /dev/null +++ b/recipeBuddy/src/app/recipePass/recipe-pass.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { Recipe } from '../DataModels/recipe'; + +@Injectable({ + providedIn: 'root', +}) +export class RecipePassService { + + private sourceRecipe: Recipe; + + constructor() { } + + public setRecipe (recipeToPass: Recipe) { + this.sourceRecipe = recipeToPass; + } + + public getRecipe (): Recipe { + return this.sourceRecipe; + } +} |