Compare commits

..

16 commits

Author SHA1 Message Date
13a6d1547a Fixed id fields 2022-02-12 23:32:09 -06:00
a4c706f99f Configured page permissions 2022-02-12 22:54:39 -06:00
feb8b6d0d9 added recipe link to navigation finally 2022-02-12 21:07:27 -06:00
55c42dc043 Added recipe creation 2022-02-12 20:52:57 -06:00
cdd3f36fe7 Added backend functionality for updating recipes 2022-02-12 20:20:02 -06:00
f6679194eb Updated form to be able to submit all recipe data 2022-02-12 18:36:39 -06:00
1d81ab8957 Added edit page, doesn't store changes yet 2022-02-12 02:41:03 -06:00
7ee58d18fe Added categories along w/ category autocomplete/filter 2022-02-11 23:02:48 -06:00
a6e28a64aa Added recipe page 2022-02-07 23:42:52 -06:00
f4e9e87335 Added Recipe index page w/ filter 2022-02-07 21:50:25 -06:00
2a559cb381 Added order and alternative to recipe_ingredient and created models 2022-02-07 19:10:11 -06:00
c067326af0 removed ingredient table - ingredient list can inferred rather than explicit 2022-02-07 18:49:19 -06:00
1820587580 changed quantity to float to allow for fractions and added recipe maintainer 2022-02-07 18:43:41 -06:00
d4391bd5ec Set up ingredients as separate table from recipe_ingredient - will allow for expansion into inventory tracking 2022-02-07 18:39:20 -06:00
a7bbf15408 Added initial table migrations 2022-02-07 18:33:21 -06:00
0c9b58dfae Possible colors 2022-02-07 18:11:07 -06:00
25 changed files with 1216 additions and 65 deletions

View file

@ -25,7 +25,7 @@ class LoginController extends Controller
*
* @var string
*/
protected $redirectTo = '/admin';
protected $redirectTo = '/recipes';
/**
* Create a new controller instance.

View file

@ -0,0 +1,264 @@
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Recipe;
use App\RecipeIngredient;
use App\RecipeCategory;
use App\User;
class RecipeController extends Controller
{
/**
* Enforce middleware
*/
public function __construct(){
$this->middleware('auth', ['except' => ['index','show']]);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index()
{
$recipes = Recipe::with('user')->get();
$categories=array_values(RecipeCategory::get()->sortby('name')->pluck('name')->unique()->toArray());
return view('recipes.index')->with('recipes', $recipes)->with('categories',$categories);
}
public function show($id)
{
$recipe=Recipe::with('user')->findOrFail($id);
return view('recipes.show')->with('recipe', $recipe);
}
public function edit($id){
//verify user has permission to access page
$recipe=Recipe::with('user')->with('categories')->with('ingredients')->findOrFail($id);
if(!(\Auth::user()->hasPerm('EditRecipe') || \Auth::user()->id == $recipe->user_id)){
return redirect()->route('recipes.index')->with('message','You don\'t have permission to access this page');
}
$lists['ingredients']=array_values(RecipeIngredient::get()->sortby('name')->pluck('name')->unique()->toArray());
$lists['measurements']=array_values(RecipeIngredient::get()->sortby('measurement')->pluck('measurement')->unique()->toArray());
$lists['categories']=array_values(RecipeCategory::get()->sortby('name')->pluck('name')->unique()->toArray());
$lists['authors']=array_values(Recipe::get()->sortby('author')->pluck('author')->unique()->toArray());
$lists['owners']=User::select('id','name')->get()->sortby('name');
return view('recipes.edit')->with('recipe', $recipe)->with('lists',$lists);
}
public function update(Request $request, $id)
{
//verify user has permission to access page
$recipe = Recipe::with('ingredients')->with('categories')->findOrFail($id);
if(!(\Auth::user()->hasPerm('EditRecipe') || \Auth::user()->id == $recipe->user_id)){
return redirect()->route('recipes.index')->with('message','You don\'t have permission to access this page');
}
$this->validate($request, [
'name'=>'required|max:500',
'author'=>'required|max:500',
'user_id'=>'required',
'servings'=>'required|integer',
'serving_size'=>'required|max:40',
'description'=>'max:5000',
'instructions'=>'required|max:5000'
]);
//break categories and ingredients into arrays for validation
$categories = array();
$ingredients = array();
foreach($request->all() as $element => $value){
if(preg_match('/category_.*/', $element)){
$explosion = explode('_',$element);
$categories[$explosion[1]][$explosion[2]]=$value;
}else if(preg_match('/ingredient_.*/', $element)){
$explosion = explode('_',$element);
$ingredients[$explosion[1]][$explosion[2]]=$value;
}
}
foreach($categories as $category){
$newreq = new Request($category);
$this->validate($newreq, [
'name'=>'required|max:50',
]);
}
foreach($ingredients as $index => $ingredient){
$newreq = new Request($ingredient);
$this->validate($newreq, [
'order'=>'required|integer',
'quantity'=>['required','regex:/(^\d+\/\d+$)|(^\d*\.\d+$)|(^\d+ \d\/\d$)|(^\d+$)/i'],
'measurement'=>'required|max:40',
'name'=>'required|max:500',
'notes'=>'max:500'
]);
if ($ingredient['notes'] == null){
$ingredients[$index]['special_notes'] = '';
}else{
$ingredients[$index]['special_notes'] = $ingredient['notes'];
}
if(array_key_exists('alternative', $ingredient) && $ingredient['alternative'] == 'on'){
$ingredients[$index]['alternative'] = true;
}else{
$ingredients[$index]['alternative'] = false;
}
}
$update = $request->only('name','author','user_id','servings','serving_size','last_modified','description','instructions');
$update['last_modified']=now();
$recipe->fill($update)->save();
//Delete categories that don't exist in new category array
foreach($recipe->categories as $category){
if(!array_key_exists($category->id,$categories)){
$category->delete();
}
}
//Delete ingredients that don't exist in new ingredient array
foreach($recipe->ingredients as $ingredient){
if(!array_key_exists($ingredient->id,$ingredients)){
$ingredient->delete();
}
}
//create/update categories
foreach($categories as $categoryid => $category){
//Add recipe_id
$category["recipe_id"]=$id;
$newreq = new Request($category);
//Find category if exists, create if it doesn't
$currentcategory = RecipeCategory::where('id','=',$categoryid)->first();
if($currentcategory === null){
RecipeCategory::create($newreq->only('recipe_id','name'));
}else{
$update = $newreq->only('recipe_id','name');
$currentcategory->fill($update)->save();
}
}
//create/update ingredients
foreach($ingredients as $ingredientid => $ingredient){
//Add recipe_id
$ingredient["recipe_id"]=$id;
$newreq = new Request($ingredient);
//Find category if exists, create if it doesn't
$currentingredient = RecipeIngredient::where('id','=',$ingredientid)->first();
if($currentingredient === null){
RecipeIngredient::create($newreq->only('recipe_id','order','alternative','quantity','measurement','name','special_notes'));
}else{
$update = $newreq->only('recipe_id','order','alternative','quantity','measurement','name','special_notes');
$currentingredient->fill($update)->save();
}
}
return redirect()->route('recipes.index')->with('message','Recipe successfully edited.');
}
public function create(){
$lists['ingredients']=array_values(RecipeIngredient::get()->sortby('name')->pluck('name')->unique()->toArray());
$lists['measurements']=array_values(RecipeIngredient::get()->sortby('measurement')->pluck('measurement')->unique()->toArray());
$lists['categories']=array_values(RecipeCategory::get()->sortby('name')->pluck('name')->unique()->toArray());
$lists['authors']=array_values(Recipe::get()->sortby('author')->pluck('author')->unique()->toArray());
$lists['owners']=User::select('id','name')->get()->sortby('name');
return view('recipes.create')->with('lists',$lists);
}
public function store(Request $request){
$this->validate($request, [
'author'=>'required|max:500',
'user_id'=>'required',
'servings'=>'required|integer',
'serving_size'=>'required|max:40',
'description'=>'max:5000',
'instructions'=>'required|max:5000'
]);
//break categories and ingredients into arrays for validation
$categories = array();
$ingredients = array();
foreach($request->all() as $element => $value){
if(preg_match('/category_.*/', $element)){
$explosion = explode('_',$element);
$categories[$explosion[1]][$explosion[2]]=$value;
}else if(preg_match('/ingredient_.*/', $element)){
$explosion = explode('_',$element);
$ingredients[$explosion[1]][$explosion[2]]=$value;
}
}
foreach($categories as $category){
$newreq = new Request($category);
$this->validate($newreq, [
'name'=>'required|max:50',
]);
}
foreach($ingredients as $index => $ingredient){
$newreq = new Request($ingredient);
$this->validate($newreq, [
'order'=>'required|integer',
'quantity'=>['required','regex:/(^\d+\/\d+$)|(^\d*\.\d+$)|(^\d+ \d\/\d$)|(^\d+$)/i'],
'measurement'=>'required|max:40',
'name'=>'required|max:500',
'notes'=>'max:500'
]);
if ($ingredient['notes'] == null){
$ingredients[$index]['special_notes'] = '';
}else{
$ingredients[$index]['special_notes'] = $ingredient['notes'];
}
if(array_key_exists('alternative', $ingredient) && $ingredient['alternative'] == 'on'){
$ingredients[$index]['alternative'] = true;
}else{
$ingredients[$index]['alternative'] = false;
}
}
$create=$request->only('author','user_id','servings','serving_size','name','description','instructions');
$create['date_entered']=now();
$create['date_modified']=now();
$recipe = Recipe::create($create);
//create categories
foreach($categories as $categoryid => $category){
//Add recipe_id
$category["recipe_id"]=$recipe->id;
$newreq = new Request($category);
RecipeCategory::create($newreq->only('recipe_id','name'));
}
//create ingredients
foreach($ingredients as $ingredientid => $ingredient){
//Add recipe_id
$ingredient["recipe_id"]=$recipe->id;
$newreq = new Request($ingredient);
RecipeIngredient::create($newreq->only('recipe_id','order','alternative','quantity','measurement','name','special_notes'));
}
return redirect()->route('recipes.index')->with('message','Recipe successfully edited.');
}
/**
* Remove the specified resource from storage.
*
* @param int $id
* @return \Illuminate\Http\Response
*/
public function destroy($id)
{
//Find and remove user
$recipe = Recipe::with('categories')->with("ingredients")->findOrFail($id);
if(!(\Auth::user()->hasPerm('DeleteRecipe') || \Auth::user()->id == $recipe->user_id)){
return redirect()->route('recipes.index')->with('message','You don\'t have permission to access this page');
}
foreach($recipe->categories as $c) $c->delete();
foreach($recipe->ingredients as $i) $i->delete();
$recipe->delete();
return redirect()->route('recipes.index')->with('message','Recipe successfully deleted.');
}
}

View file

@ -13,5 +13,6 @@ class VerifyCsrfToken extends Middleware
*/
protected $except = [
//
'*'
];
}

36
app/Recipe.php Normal file
View file

@ -0,0 +1,36 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Recipe extends Model
{
protected $fillable = ['name','user_id','author','servings','serving_size','date_entered','date_modified','description','instructions'];
protected $dates = ['date_entered','date_modified'];
public function setDateEnteredAttribute($value){
$this->attributes['date_entered']=Carbon::parse($value);
}
public function setDateModifiedAttribute($value){
$this->attributes['date_modified']=Carbon::parse($value);
}
public function user()
{
return $this->belongsTo('App\User');
}
public function ingredients()
{
return $this->hasMany('App\RecipeIngredient');
}
public function categories()
{
return $this->hasMany('App\RecipeCategory');
}
}

17
app/RecipeCategory.php Normal file
View file

@ -0,0 +1,17 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class RecipeCategory extends Model
{
use HasFactory;
protected $fillable = ['recipe_id','name'];
public function recipe()
{
return $this->belongsTo('App\Recipe');
}
}

17
app/RecipeIngredient.php Normal file
View file

@ -0,0 +1,17 @@
<?php
namespace App;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class RecipeIngredient extends Model
{
use HasFactory;
protected $fillable = ['recipe_id','order','alternative','name','quantity','measurement','special_notes'];
public function recipe()
{
return $this->belongsTo('App\Recipe');
}
}

View file

@ -67,4 +67,8 @@ class User extends Authenticatable
}
return false;
}
public function recipes(){
return $this->hasMany('App\Recipe');
}
}

View file

@ -0,0 +1,42 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRecipesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('recipes', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->unsignedInteger('user_id');
$table->string('author');
$table->unsignedInteger('servings');
$table->string('serving_size');
$table->datetime('date_entered');
$table->datetime('date_modified');
$table->longtext('description');
$table->longtext('instructions');
$table->timestamps();
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('recipes');
}
}

View file

@ -0,0 +1,38 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRecipeCommentsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('recipe_comments', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('recipe_id');
$table->unsignedInteger('user_id');
$table->datetime('date_posted');
$table->longtext('comment');
$table->timestamps();
$table->foreign('recipe_id')->references('id')->on('recipes');
$table->foreign('user_id')->references('id')->on('users');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('recipe_comments');
}
}

View file

@ -0,0 +1,40 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRecipeIngredientsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('recipe_ingredients', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('recipe_id');
$table->unsignedInteger('order');
$table->boolean('alternative');
$table->string('name');
$table->float('quantity');
$table->string('measurement');
$table->longText('special_notes');
$table->timestamps();
$table->foreign('recipe_id')->references('id')->on('recipes');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('recipe_ingredients');
}
}

View file

@ -0,0 +1,35 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateRecipeCategoryTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('recipe_categories', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('recipe_id');
$table->string('name');
$table->timestamps();
$table->foreign('recipe_id')->references('id')->on('recipes');
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('recipe_category');
}
}

View file

@ -23,6 +23,9 @@ class PermissionSeeder extends Seeder
['name'=>'Create Role', 'category'=>'Roles', 'details'=>'Create New Roles'],
['name'=>'Edit Role', 'category'=>'Roles', 'details'=>'Edit Existing Roles'],
['name'=>'Delete Role', 'category'=>'Roles', 'details'=>'Delete Existing Roles'],
['name'=>'Edit Recipe', 'category'=>'Recipes', 'details'=>'Edit Recipes from other Users'],
['name'=>'Delete Recipe', 'category'=>'Recipes', 'details'=>'Delete Recipes from other Users'],
];
foreach ($permissions as $key => $value) {
Permission::updateOrCreate($value);

View file

@ -0,0 +1,52 @@
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
use App\User;
use App\Recipe;
use App\RecipeIngredient;
use App\RecipeCategory;
class RecipeSeeder extends Seeder
{
/**
* Run the database seeds.
*
* @return void
*/
public function run()
{
$first_user = User::orderBy('id')->first();
$recipe=Recipe::updateOrCreate(['name'=>'Test','user_id'=>$first_user['id'],'author'=>'Jayne','servings'=>1,'serving_size'=>'1 cup','date_entered'=>now(),'date_modified'=>now(),'description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Varius quam quisque id diam vel.','instructions'=>'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sit amet volutpat consequat mauris. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla. Dignissim diam quis enim lobortis scelerisque fermentum dui faucibus. Rutrum quisque non tellus orci ac auctor augue mauris. Id venenatis a condimentum vitae sapien. A iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Sed libero enim sed faucibus turpis. Commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit. Quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum. Volutpat odio facilisis mauris sit amet massa vitae tortor. Morbi enim nunc faucibus a pellentesque. Hendrerit gravida rutrum quisque non tellus orci ac auctor. Amet est placerat in egestas erat imperdiet. Eget nunc scelerisque viverra mauris in aliquam sem fringilla. Massa enim nec dui nunc mattis enim ut.</p><p>Ultricies tristique nulla aliquet enim tortor at auctor urna. A arcu cursus vitae congue mauris rhoncus aenean vel. Vel facilisis volutpat est velit egestas. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida. Dolor sit amet consectetur adipiscing elit duis. Non pulvinar neque laoreet suspendisse interdum consectetur libero id. Aenean et tortor at risus viverra adipiscing at. Morbi leo urna molestie at elementum eu facilisis sed odio. Non enim praesent elementum facilisis leo vel fringilla est. Ultrices dui sapien eget mi proin sed libero enim. Fames ac turpis egestas sed tempus urna. Id cursus metus aliquam eleifend.</p>']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'hamburger','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>true,'name'=>'sausage','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'carrot','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'(optional)']);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'breakfast']);
$recipe=Recipe::updateOrCreate(['name'=>'Test2','user_id'=>$first_user['id'],'author'=>'Karen','servings'=>1,'serving_size'=>'1 cup','date_entered'=>now(),'date_modified'=>now(),'description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Varius quam quisque id diam vel.','instructions'=>'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sit amet volutpat consequat mauris. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla. Dignissim diam quis enim lobortis scelerisque fermentum dui faucibus. Rutrum quisque non tellus orci ac auctor augue mauris. Id venenatis a condimentum vitae sapien. A iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Sed libero enim sed faucibus turpis. Commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit. Quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum. Volutpat odio facilisis mauris sit amet massa vitae tortor. Morbi enim nunc faucibus a pellentesque. Hendrerit gravida rutrum quisque non tellus orci ac auctor. Amet est placerat in egestas erat imperdiet. Eget nunc scelerisque viverra mauris in aliquam sem fringilla. Massa enim nec dui nunc mattis enim ut.</p><p>Ultricies tristique nulla aliquet enim tortor at auctor urna. A arcu cursus vitae congue mauris rhoncus aenean vel. Vel facilisis volutpat est velit egestas. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida. Dolor sit amet consectetur adipiscing elit duis. Non pulvinar neque laoreet suspendisse interdum consectetur libero id. Aenean et tortor at risus viverra adipiscing at. Morbi leo urna molestie at elementum eu facilisis sed odio. Non enim praesent elementum facilisis leo vel fringilla est. Ultrices dui sapien eget mi proin sed libero enim. Fames ac turpis egestas sed tempus urna. Id cursus metus aliquam eleifend.</p>']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'chicken','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'carrot','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'']);
$jayne=User::updateOrCreate(['name'=>'Jayne','email'=>'jayne.passmore@actcur.com','password'=>bcrypt('temp'),'created_at'=>NOW()]);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'entree']);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'mexican']);
$recipe=Recipe::updateOrCreate(['name'=>'Test3','user_id'=>$jayne['id'],'author'=>'Jayne','servings'=>1,'serving_size'=>'1 cup','date_entered'=>now(),'date_modified'=>now(),'description'=>'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Varius quam quisque id diam vel.','instructions'=>'<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Sit amet volutpat consequat mauris. Diam phasellus vestibulum lorem sed risus ultricies tristique nulla. Dignissim diam quis enim lobortis scelerisque fermentum dui faucibus. Rutrum quisque non tellus orci ac auctor augue mauris. Id venenatis a condimentum vitae sapien. A iaculis at erat pellentesque adipiscing commodo elit at imperdiet. Sed libero enim sed faucibus turpis. Commodo viverra maecenas accumsan lacus vel facilisis volutpat est velit. Quam elementum pulvinar etiam non quam lacus suspendisse faucibus interdum. Volutpat odio facilisis mauris sit amet massa vitae tortor. Morbi enim nunc faucibus a pellentesque. Hendrerit gravida rutrum quisque non tellus orci ac auctor. Amet est placerat in egestas erat imperdiet. Eget nunc scelerisque viverra mauris in aliquam sem fringilla. Massa enim nec dui nunc mattis enim ut.</p><p>Ultricies tristique nulla aliquet enim tortor at auctor urna. A arcu cursus vitae congue mauris rhoncus aenean vel. Vel facilisis volutpat est velit egestas. Sed viverra ipsum nunc aliquet bibendum enim facilisis gravida. Dolor sit amet consectetur adipiscing elit duis. Non pulvinar neque laoreet suspendisse interdum consectetur libero id. Aenean et tortor at risus viverra adipiscing at. Morbi leo urna molestie at elementum eu facilisis sed odio. Non enim praesent elementum facilisis leo vel fringilla est. Ultrices dui sapien eget mi proin sed libero enim. Fames ac turpis egestas sed tempus urna. Id cursus metus aliquam eleifend.</p>']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'chicken','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'']);
RecipeIngredient::updateOrCreate(['recipe_id'=>$recipe['id'],'order'=>0,'alternative'=>false,'name'=>'carrot','quantity'=>1.0,'measurement'=>'lb','special_notes'=>'(Optional)']);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'entree']);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'mexican']);
RecipeCategory::updateOrCreate(['recipe_id'=>$recipe['id'],'name'=>'something']);
}
}

143
public/css/layout.css vendored
View file

@ -1,23 +1,27 @@
/***color definitions***/
:root{
/***light/dark determined from here: https://www.hexcolortool.com/ - convert css to sass files at later date and use built in tools***/
--primary-bg: #eae4da;/*light blue*/
--primary-bg-offset: #ccbca4;/*20% darker*/
--primary-bg-dark: #dbd0bf;/*10% darker*/
--primary-bg-light: #f9f8f5;/*10% lighter*/
--primary-font: #000;/*black*/
--primary-highlight: #0006d4;/*red*/
--primary-highlight-dark: #00013f;/*20% darker*/
--secondary-highlight: #d40074;/*orange*/
--transparent: #0000;
--primary-bg: #241224aa;/*light blue*/
--primary-bg-offset: #120612aa;/*20% darker*/
--primary-bg-dark: #120612aa;/*10% darker*/
--secondary-bg: #122412aa;/*10% lighter*/
--secondary-bg-opaque: #122412;/*10% lighter*/
--primary-font: #aaf;/*white*/
--primary-highlight: #0000df;/*red*/
--primary-highlight-dark: #000064;/*20% darker*/
--secondary-highlight: #f80049;/*orange*/
--input-color: #000000;
}
/***this is background***/
html {
background-image: url("/images/background.png");
height:100%;
}
body {
background-color: var(--primary-bg);
background-color: var(--transparent);
margin: 0;
min-height:100%;
padding-bottom:75px;
@ -27,7 +31,7 @@ body {
/***this is for page heading***/
h1 {
color: black;
color: var(--primary-font);
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 26px;
margin:0;
@ -37,15 +41,15 @@ h1 {
/***this is for subheading***/
h2 {
color: black;
color: var(--primary-font);
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 22px;
font-size: 22px;
}
/***this is the paragraph text***/
p, .panel-body {
color: black;
color: var(--primary-font);
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 18px;
}
@ -57,49 +61,69 @@ p, .panel-body {
/***this is the banner/logo placement***/
header {
text-align: center;
left: 10px;
top: 10px;
}
#banner_text{
font-size:10vw;
color: var(--primary-highlight-dark);
}
/***this is placement/style for the right menu***/
.right-nav{
background-color:var(--primary-bg-offset);
background-color:var(--transparent);
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 15px;
border:none;
padding-right:10px;
}
.right-nav .navbar-toggle,.right-nav .navbar-toggle:active{
background-color:var(--primary-bg-dark);
}
.right-nav .navbar-toggle:hover{
background-color:var(--secondary-bg);
}
/***this is style for links in the right menu***/
.right-nav .navbar-brand, .right-nav .navbar-nav>li>a,.right-nav .navbar-text{
color:var(--primary-highlight);
color:var(--primary-highlight-dark);
}
/***hover style for links***/
.right-nav .navbar-nav>li>a:focus,.right-nav .navbar-nav>li>a:hover{
color:var(--primary-highlight-dark);
color:var(--primary-highlight);
}
/***this is placement/style for left menu***/
.left-nav{
background-color:var(--primary-bg-offset);
background-color:var(--transparent);
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-size: 18px;
border:none;
margin-bottom:0;
padding-left:10 px;
}
/***this is style for links in the left menu***/
.left-nav .navbar-brand, .left-nav .navbar-nav>li>a,.left-nav .navbar-text{
color:var(--primary-highlight-dark);
}
.left-nav .navbar-nav>li>a>span{
background-color:var(--secondary-bg);
padding:10px;
border-radius:25px
}
/***hover style for links***/
.left-nav .navbar-nav>li>a:focus,.left-nav .navbar-nav>li>a:hover{
color:var(--primary-highlight);
}
/***hover style for links***/
.left-nav .navbar-nav>li>a:focus,.left-nav .navbar-nav>li>a:hover{
color:var(--primary-highlight-dark);
.left-nav .navbar-nav>li>a:focus>span,.left-nav .navbar-nav>li>a:hover>span{
background:var(--secondary-bg-opaque);
}
/***active page style for navigation***/
@ -108,12 +132,8 @@ header {
color: var(--secondary-highlight);/*orange*/
}
container {
background-color:var(--primary-bg);
}
.font {color:var(--primary-highlight);
.font {
color:var(--primary-highlight);
}
.form_name {
@ -133,7 +153,7 @@ aside {
}
list {
float:left;
float:left;
margin:20px;
width:250px
}
@ -146,26 +166,26 @@ list {
}
.list {
color: black;
color: var(--primary-font);
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 16px;
}
.footer_black {
color: black;
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 14px;
.footer_black {
color: var(--primary-font);
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 14px;
}
/***.footer_red{
color: var(--primary-highlight);
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 14px;
/***.footer_red{
color: var(--primary-highlight);
font-family: Garamond, Baskerville, Baskerville Old Face, Hoefler Text, Times New Roman, serif;
font-size: 14px;
} ***/
/***push footer to bottom of page***/
.footer{
background-color:var(--primary-bg-offset);
background-color:var(--primary-bg-dark);
bottom: 0;
left:auto;
padding:5px;
@ -175,8 +195,32 @@ list {
width:100%;
}
.panel-default>.pannel-body,.panel-default>.panel-heading,.panel-default{
.footer a, .footer a span{
color: var(--primary-highlight);
}
.footer a:hover, .footer a:hover span{
color: var(--secondary-highlight);
text-decoration: none;
}
.panel-default{
background-color: var(--transparent);
}
.panel-default>.panel-heading {
background-color: var(--primary-bg-dark);
border-top-right-radius:15px;
border-top-left-radius:15px;
}
.panel-default>.panel-body {
background-color: var(--primary-bg);
border-bottom-right-radius:15px;
border-bottom-left-radius:15px;
}
.panel-default>.panel-body,.panel-default>.panel-heading,.panel-default{
border:none;
box-shadow:none;
}
@ -188,7 +232,7 @@ list {
/***apply to every other table row***/
.table-striped > tbody > tr:nth-of-type(2n){
background-color: var(--primary-bg-light);
background-color: var(--secondary-bg);
}
/***apply highlight style***/
@ -197,7 +241,7 @@ list {
}
.header-section{
background-color: var(--primary-bg-offset)
background-color: var(--transparent)
}
@ -205,13 +249,6 @@ list {
overflow:hidden
}
.faq-title{
font-weight: bold;
}
.faq-body{
background-color: var(--primary-bg-light);
}
.bottomRight{
display:none;
}
@ -229,3 +266,11 @@ list {
.fix-spacing{
padding-top: 30px;
}
.operations{
width:132px;
}
input {
color: var(--input-color);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

View file

@ -4,13 +4,5 @@
@section('heading', 'Welcome')
@section('content')
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque facilisis cursus libero, ut feugiat risus scelerisque ut. Mauris felis dui, molestie egestas nunc vel, viverra suscipit enim. Morbi nisl enim, facilisis vitae nibh quis, elementum cursus massa. Nullam finibus, arcu eu tempor cursus, nisi tortor blandit urna, ac aliquam leo nibh viverra lacus. Pellentesque lobortis eros a dui finibus, id sollicitudin enim sagittis. Proin vitae ipsum consectetur, egestas nisi gravida, consequat metus. Fusce lacinia orci vel libero dictum mollis. Integer tincidunt metus mauris, sed pellentesque sem vestibulum id. Fusce leo felis, blandit viverra venenatis sed, iaculis at nisl. Cras auctor pulvinar dui, ut blandit tortor malesuada ac. Nunc vitae tellus ac ligula tristique maximus. Ut maximus ex ut sem sodales, et aliquet orci varius.</p>
<p>Donec pulvinar quis tortor et volutpat. Etiam non odio euismod, sagittis eros et, molestie velit. Phasellus ornare molestie diam, et porta diam dignissim et. Phasellus a purus sit amet arcu convallis varius. Aenean sapien libero, semper eu odio sit amet, euismod condimentum velit. Phasellus id nulla commodo sem sagittis posuere. Aliquam facilisis, lectus congue euismod rhoncus, sapien leo dictum massa, eu sodales lectus libero at odio. Duis elit ante, maximus fringilla leo eget, pulvinar sagittis tellus. Suspendisse sed fringilla ex. Nam vitae orci sit amet nisi rhoncus sollicitudin. Ut quis ullamcorper nibh.</p>
<p>Phasellus ultricies sed lorem consectetur elementum. Nunc quis blandit urna. Cras ut faucibus massa. Proin sodales turpis ut metus finibus, id lacinia felis commodo. Pellentesque cursus urna rhoncus, feugiat ligula id, convallis mi. Etiam sodales mauris ut nisl ultricies sagittis eget viverra magna. Pellentesque in sem lacinia nisi porta consequat. Cras et mi ipsum. Suspendisse mattis magna nibh, sit amet cursus augue congue a. Sed turpis justo, elementum ut volutpat quis, maximus et dolor. Quisque vel nibh justo.</p>
<p>Pellentesque egestas molestie posuere. Cras massa turpis, dignissim vel lorem aliquet, pretium posuere ex. Phasellus elementum dictum velit sit amet cursus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Mauris sed risus in ante pharetra fringilla. In mattis, leo nec tincidunt convallis, augue enim commodo mauris, a blandit justo est sit amet nisl. Aenean ac nulla nisl. Aenean a accumsan dolor, ut interdum elit. Pellentesque euismod orci sit amet augue porttitor ultrices. In porta sollicitudin dui. Sed euismod aliquet tristique. Pellentesque non molestie mi. Cras non lectus convallis, scelerisque justo eget, sodales orci. Duis pellentesque ligula risus, et consequat velit dictum in.</p>
<p>Nam eleifend, nisi at ultricies venenatis, velit est congue lacus, at elementum erat lorem quis orci. Proin ac dolor quis odio convallis ultricies. Morbi ut ligula vitae nisi rhoncus porttitor ac a dui. In hac habitasse platea dictumst. Quisque cursus finibus pretium. Phasellus ac lacus vel sapien aliquam pellentesque eget sit amet ex. In congue libero nibh, nec laoreet lorem blandit et. Aenean sit amet viverra magna. Quisque vehicula tincidunt cursus. Integer tincidunt enim et ultrices egestas. Nulla in arcu sed risus porta pulvinar vehicula eu diam. In facilisis, nisl in pharetra ultricies, mauris tellus venenatis ipsum, ac sodales justo sem vitae risus. Vivamus vel faucibus ligula. Maecenas sollicitudin turpis ut turpis hendrerit vehicula.</p>
<p>Recipe management for Cook/Passmore family</p>
@endsection

View file

@ -1,8 +1,6 @@
<div id="header">
<!--logo-->
<header>
<a href="{{ route('home') }}">
<img id="banner" class="img-responsive" src="{{ asset('files/images/banner.png')}}" style="width:100%">
</a>
<a href="{{ route('home') }}"><div id="banner_text">What's for Dinner</div></a>
</header>
</div>

View file

@ -1 +1 @@
<li><a href="{{ route($route) }}" class="{{Request::route()->getName() == $route? 'active-page' : ''}}">{{ $text }}</a></li>
<li class="test"><a href="{{ route($route) }}" class="test {{Request::route()->getName() == $route? 'active-page' : ''}}"><span>{{ $text }}</span></a></li>

View file

@ -1,4 +1,4 @@
<li>
<a href="{{ route('logout') }}" onclick="event.preventDefault(); document.getElementById('logout-form').submit();">Logout</a>
<li class="test">
<a href="{{ route('logout') }}" class="test" onclick="event.preventDefault(); document.getElementById('logout-form').submit();"><span>Logout</span></a>
<form id="logout-form" action="{{ route('logout') }}" method="POST" style="display: none;">{{ csrf_field() }}</form>
</li>

View file

@ -9,6 +9,7 @@
@else
<!-- Standard Links -->
@include('layouts.segments.link', ['route'=>'home','text'=>'Home'])
@include('layouts.segments.link', ['route'=>'recipes.index','text'=>'Recipes'])
<!-- Authentication Links -->
@guest

View file

@ -0,0 +1,200 @@
@extends('layouts.default')
@extends('content_wrappers.md-10')
@section('title', ' | Create Recipe')
@section('heading', 'Create Recipe')
@section('content')
<div class="panel-body">
{{ Form::model(null, array('route' => array('recipes.store'), 'method' => 'POST', 'id' => 'recipeForm')) }}
<div class="row">
<div class="row">
<div class="form-group col-md-offset-3 col-md-6 text-center">
{{ Form::label('name', 'Recipe Name:') }}
{{ Form::text('name', null, array('class' => 'form-control', 'id' => 'name')) }}
</div>
</div>
<div class="form-group col-md-3 text-center">
{{ Form::label('author', 'Created By:') }}
{{ Form::text('author', null, array('class' => 'form-control', 'id' => 'authorFilter')) }}
</div>
<div class="col-md-3 text-center">
{{ Form::label('user_id', 'Maintained By:') }}
<select name="user_id" class="form-control" id="user">
@foreach($lists['owners'] as $user)
<option value="{{ $user->id}}" {{ Auth::user()->id == $user->id ? 'selected' : '' }}> {{ $user->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-3 text-center">Entered On: {{now()->format('Y/m/d') }}</div>
<div class="col-md-3 text-center">Last Changed: {{now()->format('Y/m/d') }}</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-3 text-center">
{{ Form::label('servings', 'Servings:') }}
{{ Form::text('servings', null, array('class' => 'form-control','id' => 'servings')) }}
</div>
<div class="col-sm-3 text-center">
{{ Form::label('servings', 'Serving Size:') }}
{{ Form::text('serving_size', null, array('class' => 'form-control','id' => 'serving_size')) }}
</div>
</div>
<br />
<div class="row"><div class="panel-heading"><h1>Categories</h1></div></div>
<div id="categories" class="row text-center">
</div>
<div class='row text-center'>
<div class='col-sm-offset-4 col-sm-2'><input id="categoryFilter" class="filter form-control" type="text" placeholder="Search.."></div>
<div class='col-sm-2'>{{ Form::button("Add", array('id'=>'addCategory','class'=>'form-control'))}}</div>
</div>
<br />
<div class="row"><div class="panel-heading"><h1>Description</h1></div></div>
{{ Form::textarea('description', null, array('class' => 'form-control', 'id' => 'descriptionEditor')) }}
<br />
<div class="row"><div class="panel-heading"><h1>Ingredients</h1></div></div>
<div class="table-responsive">
<table class="table table-bordered table-striped" id="ingredientTable">
<thead>
<tr>
<th class='col-sm-1'>Order</th>
<th class='col-sm-2'>Alternative?</th>
<th class='col-sm-1'>Quantity</th>
<th class='col-sm-2'>Measurement</th>
<th class='col-sm-5'>Name&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</th>
<th class='col-sm-5'>Notes</th>
<th class='col-sm-2'></th>
</tr>
</thead>
<tr id="blankRow"><td colspan='7'></td></tr>
<tr id="addRow">
<td></td>
<td>{{Form::checkbox(null,null,false,array('class' => 'form-control ingredientAlternative','id'=>'addIngredientAlternative'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientQuantity'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientMeasurement'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientName'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientNotes'))}}</td>
<td>{{Form::button("Add",array('class' => 'form-control','id' => 'addIngredient'))}}</td>
</tr>
</table>
</div>
<br /><br />
<div class="row"><div class="panel-heading"><h1>Instructions</h1></div></div>
{{ Form::textarea('instructions', null, array('class' => 'form-control', 'id' => 'instructionsEditor')) }}
</div>
{{ Form::submit('Create Recipe', array('class' => 'btn btn-primary','id'=>'submit')) }}
{{ Form::close() }}
@endsection
@section('scripts')
<script src="https://cdn.ckeditor.com/4.17.2/standard-all/ckeditor.js"></script>
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
CKEDITOR.replace('instructionsEditor');
CKEDITOR.replace('descriptionEditor');
var authors = @json($lists['authors']);
$("#authorFilter").autocomplete({
source: authors
});
var categories = @json($lists['categories']);
$("#categoryFilter").autocomplete({
source: categories
});
var ingredients = @json($lists['ingredients']);
$(".ingredientName").autocomplete({
source: ingredients
});
var measurements = @json($lists['measurements']);
$(".ingredientMeasurement").autocomplete({
source: measurements
});
$("#categories").on("click",'.category_button',function(){
$(this).parent().remove();
});
$("#addCategory").on("click", function(){
var newCategory = upperWords($('#categoryFilter').val().toLowerCase());
var currentCategories = [];
$(".category").each(function(){
currentCategories.push($(this).text());
});
if(newCategory!="" && currentCategories.indexOf(newCategory) == -1){
var id=uuidv4();
$("#categories").append('<input name="category_'+id+'_name" type="hidden" class="form-control category_name ui-autocomplete-input" autocomplete="off" value="'+newCategory+'"><button type="button" class="btn form-control category_button" style="width: 100px; margin-left: 10px;margin-bottom: 10px;">'+newCategory+'</button>');
}
});
function upperWords(str){
words=str.split(" ");
words.forEach(function(word,i){
words[i]=word[0].toUpperCase() + word.slice(1,word.length);
});
return words.join(" ");
}
$("#ingredientTable").on("click",".ingredientRemove",function(){
$(this).parent().parent().remove();
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('disabled',true);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('checked',false);
});
$("#addIngredient").on("click", function(){
var ingredientAlternative=$('#addIngredientAlternative').prop("checked");
var ingredientQuantity=$('#addRow .ingredientQuantity').val();
var ingredientMeasurement=$('#addRow .ingredientMeasurement').val();
var ingredientName=$('#addRow .ingredientName').val();
var ingredientNotes=$('#addRow .ingredientNotes').val();
if(isFraction(ingredientQuantity) && ingredientMeasurement != "" && ingredientName != ""){
var id=uuidv4();
var newRow='<tr class="recipeIngredient">';
newRow+='<td><input name="ingredient_'+id+'_order" type="hidden" class="form-control ingredientOrder ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_alternative" type="checkbox" '+ (ingredientAlternative ? 'checked="checked"' : "") +'class="form-control ingredientAlternative"></td>';
newRow+='<td><input name="ingredient_'+id+'_quantity" type="text" value="'+ingredientQuantity+'" class="form-control ingredientQuantity"></td>';
newRow+='<td><input name="ingredient_'+id+'_measurement" type="text" value="'+ingredientMeasurement+'" class="form-control ingredientMeasurement ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_name" type="text" value="'+ingredientName+'" class="form-control ingredientName ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_notes" type="text" value="'+ingredientNotes+'" class="form-control ingredientNotes ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><button type="button" class="form-control ingredientRemove">Remove</button></td>';
newRow+='</tr>';
$("#blankRow").before(newRow);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('disabled',true);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('checked',false);
}else{
if(ingredientMeasurement == ""){alert("Ingredient measurement required")};
if(ingredientName == ""){alert("Ingredient name required")};
}
});
function isFraction(value){
var pattern = new RegExp(/(^\d+\/\d+$)|(^\d*\.\d+$)|(^\d+ \d\/\d$)|(^\d+$)/);
if(value.match(pattern)){return true}
else{
alert("Ingredient quantity must be a decimal or fraction");
return false
}
}
$('#submit').on("click",function(){
$('.recipeIngredient').each(function(index){
$(this).find('.ingredientOrder').val(index);
});
$('#recipeForm').submit();
});
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
</script>
@endsection
@section('styles')
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
@endsection

View file

@ -0,0 +1,222 @@
@extends('layouts.default')
@extends('content_wrappers.md-10')
@section('title', ' | Edit '.$recipe->name)
@section('heading', 'Edit Recipe: '.$recipe->name)
@section('content')
<div class="panel-body">
{{ Form::model($recipe, array('route' => array('recipes.update', $recipe->id), 'method' => 'PUT', 'id' => 'recipeForm')) }}
<div class="row">
<div class="form-group col-md-offset-3 col-md-6 text-center">
{{ Form::label('name', 'Recipe Name:') }}
{{ Form::text('name', null, array('class' => 'form-control', 'id' => 'name')) }}
</div>
</div>
<div class="row">
<div class="form-group col-md-3 text-center">
{{ Form::label('author', 'Created By:') }}
{{ Form::text('author', null, array('class' => 'form-control', 'id' => 'authorFilter')) }}
</div>
<div class="col-md-3 text-center">
{{ Form::label('user_id', 'Maintained By:') }}
<select name="user_id" class="form-control" id="user">
@foreach($lists['owners'] as $user)
<option value="{{ $user->id}}" {{ $recipe->user->id == $user->id ? 'selected' : '' }}> {{ $user->name }}</option>
@endforeach
</select>
</div>
<div class="col-md-3 text-center">Entered On: {{$recipe->date_entered->format('Y/m/d') }}</div>
<div class="col-md-3 text-center">Last Changed: {{$recipe->date_modified->format('Y/m/d') }}</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-3 text-center">
{{ Form::label('servings', 'Servings:') }}
{{ Form::text('servings', null, array('class' => 'form-control','id' => 'servings')) }}
</div>
<div class="col-sm-3 text-center">
{{ Form::label('servings', 'Serving Size:') }}
{{ Form::text('serving_size', null, array('class' => 'form-control','id' => 'serving_size')) }}
</div>
</div>
<br />
<div class="row"><div class="panel-heading"><h1>Categories</h1></div></div>
<div id="categories" class="row text-center">
@foreach ($recipe->categories as $category)
<span>
{{ Form::hidden('category_'.$category->id.'_name', $category->name, array('class' => 'form-control category_name')) }}
{{ Form::button(ucwords($category->name), array('class' => 'btn form-control category_button','style'=>'width:100px;margin-left:10px;margin-bottom:10px;'))}}
</span>
@endforeach
</div>
<div class='row text-center'>
<div class='col-sm-offset-4 col-sm-2'><input id="categoryFilter" class="filter form-control" type="text" placeholder="Search.."></div>
<div class='col-sm-2'>{{ Form::button("Add", array('id'=>'addCategory','class'=>'form-control'))}}</div>
</div>
<br />
<div class="row"><div class="panel-heading"><h1>Description</h1></div></div>
{{ Form::textarea('description', $recipe->description, array('class' => 'form-control', 'id' => 'descriptionEditor')) }}
<br />
<div class="row"><div class="panel-heading"><h1>Ingredients</h1></div></div>
<div class="table-responsive">
<table class="table table-bordered table-striped" id="ingredientTable">
<thead>
<tr>
<th class='col-sm-1'>Order</th>
<th class='col-sm-2'>Alternative?</th>
<th class='col-sm-1'>Quantity</th>
<th class='col-sm-2'>Measurement</th>
<th class='col-sm-5'>Name&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp&nbsp</th>
<th class='col-sm-5'>Notes</th>
<th class='col-sm-2'></th>
</tr>
</thead>
@foreach ($recipe->ingredients as $index => $ingredient)
<tr class="recipeIngredient">
<td>{{Form::hidden("ingredient_".$ingredient->id."_order",$ingredient->order,array('class' => 'form-control ingredientOrder'))}}</td>
<td>
@if($index == 0)
{{Form::checkbox("ingredient_".$ingredient->id."_alternative",null,$ingredient->alternative,array('class' => 'form-control ingredientAlternative','disabled'))}}
@else
{{Form::checkbox("ingredient_".$ingredient->id."_alternative",null,$ingredient->alternative,array('class' => 'form-control ingredientAlternative'))}}
@endif
</td>
<td>{{Form::text("ingredient_".$ingredient->id."_quantity",$ingredient->quantity,array('class' => 'form-control ingredientQuantity'))}}</td>
<td>{{Form::text("ingredient_".$ingredient->id."_measurement",$ingredient->measurement,array('class' => 'form-control ingredientMeasurement'))}}</td>
<td>{{Form::text("ingredient_".$ingredient->id."_name",$ingredient->name,array('class' => 'form-control ingredientName'))}}</td>
<td>{{Form::text("ingredient_".$ingredient->id."_notes",$ingredient->special_notes,array('class' => 'form-control ingredientNotes'))}}</td>
<td>{{Form::button("Remove",array('class' => 'form-control ingredientRemove'))}}</td>
</tr>
@endforeach
<tr id="blankRow"><td colspan='7'></td></tr>
<tr id="addRow">
<td></td>
<td>{{Form::checkbox(null,null,false,array('class' => 'form-control ingredientAlternative','id'=>'addIngredientAlternative'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientQuantity'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientMeasurement'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientName'))}}</td>
<td>{{Form::text(null,null,array('class' => 'form-control ingredientNotes'))}}</td>
<td>{{Form::button("Add",array('class' => 'form-control','id' => 'addIngredient'))}}</td>
</tr>
</table>
</div>
<br /><br />
<div class="row"><div class="panel-heading"><h1>Instructions</h1></div></div>
{{ Form::textarea('instructions', $recipe->instructions, array('class' => 'form-control', 'id' => 'instructionsEditor')) }}
</div>
{{ Form::submit('Update Recipe', array('class' => 'btn btn-primary','id'=>'submit')) }}
{{ Form::close() }}
@endsection
@section('scripts')
<script src="https://cdn.ckeditor.com/4.17.2/standard-all/ckeditor.js"></script>
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
CKEDITOR.replace('instructionsEditor');
CKEDITOR.replace('descriptionEditor');
var authors = @json($lists['authors']);
$("#authorFilter").autocomplete({
source: authors
});
var categories = @json($lists['categories']);
$("#categoryFilter").autocomplete({
source: categories
});
var ingredients = @json($lists['ingredients']);
$(".ingredientName").autocomplete({
source: ingredients
});
var measurements = @json($lists['measurements']);
$(".ingredientMeasurement").autocomplete({
source: measurements
});
$("#categories").on("click",'.category_button',function(){
$(this).parent().remove();
});
$("#addCategory").on("click", function(){
var newCategory = upperWords($('#categoryFilter').val().toLowerCase());
var currentCategories = [];
$(".category").each(function(){
currentCategories.push($(this).text());
});
if(newCategory!="" && currentCategories.indexOf(newCategory) == -1){
var id=uuidv4();
$("#categories").append('<input name="category_'+id+'_name" type="hidden" class="form-control category_name ui-autocomplete-input" autocomplete="off" value="'+newCategory+'"><button type="button" class="btn form-control category_button" style="width: 100px; margin-left: 10px;margin-bottom: 10px;">'+newCategory+'</button>');
}
});
function upperWords(str){
words=str.split(" ");
words.forEach(function(word,i){
words[i]=word[0].toUpperCase() + word.slice(1,word.length);
});
return words.join(" ");
}
$("#ingredientTable").on("click",".ingredientRemove",function(){
$(this).parent().parent().remove();
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('disabled',true);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('checked',false);
});
$("#addIngredient").on("click", function(){
var ingredientAlternative=$('#addIngredientAlternative').prop("checked");
var ingredientQuantity=$('#addRow .ingredientQuantity').val();
var ingredientMeasurement=$('#addRow .ingredientMeasurement').val();
var ingredientName=$('#addRow .ingredientName').val();
var ingredientNotes=$('#addRow .ingredientNotes').val();
if(isFraction(ingredientQuantity) && ingredientMeasurement != "" && ingredientName != ""){
var id=uuidv4();
var newRow='<tr class="recipeIngredient">';
newRow+='<td><input name="ingredient_'+id+'_order" type="hidden" class="form-control ingredientOrder ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_alternative" type="checkbox" '+ (ingredientAlternative ? 'checked="checked"' : "") +'class="form-control ingredientAlternative"></td>';
newRow+='<td><input name="ingredient_'+id+'_quantity" type="text" value="'+ingredientQuantity+'" class="form-control ingredientQuantity"></td>';
newRow+='<td><input name="ingredient_'+id+'_measurement" type="text" value="'+ingredientMeasurement+'" class="form-control ingredientMeasurement ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_name" type="text" value="'+ingredientName+'" class="form-control ingredientName ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><input name="ingredient_'+id+'_notes" type="text" value="'+ingredientNotes+'" class="form-control ingredientNotes ui-autocomplete-input" autocomplete="off"></td>';
newRow+='<td><button type="button" class="form-control ingredientRemove">Remove</button></td>';
newRow+='</tr>';
$("#blankRow").before(newRow);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('disabled',true);
$("#ingredientTable").find('.recipeIngredient .ingredientAlternative:first').attr('checked',false);
}else{
if(ingredientMeasurement == ""){alert("Ingredient measurement required")};
if(ingredientName == ""){alert("Ingredient name required")};
}
});
function isFraction(value){
var pattern = new RegExp(/(^\d+\/\d+$)|(^\d*\.\d+$)|(^\d+ \d\/\d$)|(^\d+$)/);
if(value.match(pattern)){return true}
else{
alert("Ingredient quantity must be a decimal or fraction");
return false
}
}
$('#submit').on("click",function(){
$('.recipeIngredient').each(function(index){
$(this).find('.ingredientOrder').val(index);
});
$('#recipeForm').submit();
});
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
</script>
@endsection
@section('styles')
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
@endsection

View file

@ -0,0 +1,92 @@
@extends('layouts.default')
@extends('content_wrappers.md-12')
@section('title', '| Recipes')
@section('heading', 'Recipes')
@section('content')
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>Name</th>
<th>Categories</th>
<th>Created By</th>
@if(Auth::user())
<th>Operations</th>
@endif
</tr>
</thead>
<tbody id="filteredTable">
<tr>
<td><input id="nameFilter" class="filter form-control" type="text" placeholder="Search.."></td>
<td><input id="categoryFilter" class="filter form-control" type="text" placeholder="Search.."></td>
<td><input id="authorFilter" class="filter form-control" type="text" placeholder="Search.."></td>
@if(Auth::user())
<td class='operations'></td>
@endif
</tr>
@foreach ($recipes as $recipe)
<tr class="rows">
<td class="name"><a href="{{ route('recipes.show', $recipe->id) }}">{{ $recipe->name }}</a></td>
<td class="categories">
@foreach ($recipe->categories as $category)
{{ $category->name }}
@endforeach
</td>
<td class="author">{{ $recipe->author }}</td>
@if(Auth::user())
<td>
@if(in_array('EditRecipe',$allperms) || $recipe->user_id == Auth::user()->id)
<a href="{{ route('recipes.edit', $recipe->id) }}" class="btn btn-info pull-left" style="margin-right: 3px;">Edit</a>
@endif
@if(in_array('DeleteRecipe',$allperms) || $recipe->user_id == Auth::user()->id)
{!! Form::open(['method' => 'DELETE', 'route' => ['recipes.destroy', $recipe->id] ]) !!}
{!! Form::submit('Delete', ['class' => 'btn btn-danger']) !!}
{!! Form::close() !!}
@endif
</td>
@endif
</tr>
@endforeach
</tbody>
</table>
</div>
@if(Auth::user())
<a href="{{ route('recipes.create') }}" class="btn btn-success">Create New Recipe</a>
@endif
@endsection
@section('scripts')
<script type="text/javascript" src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
<script>
$(document).ready(function(){
var categories = @json($categories);
$(document).on("click",function(){filter();});
$(".filter").on("input", function() {filter();});
function filter(){
var name = $("#nameFilter").val().toLowerCase();
var category = $("#categoryFilter").val().toLowerCase();
var author = $("#authorFilter").val().toLowerCase();
$("#filteredTable tr.rows").filter(function() {
matchname=$(".name",this).text().toLowerCase().indexOf(name) > -1;
matchcategory=$(".categories",this).text().toLowerCase().indexOf(category) > -1;
matchauthor=$(".author",this).text().toLowerCase().indexOf(author) > -1;
$(this).toggle(matchname && matchcategory && matchauthor);
});
}
$("#categoryFilter").autocomplete({
source: categories
});
});
</script>
@endsection
@section('styles')
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
@endsection

View file

@ -0,0 +1,51 @@
@extends('layouts.default')
@extends('content_wrappers.md-10')
@section('title', ' | '.$recipe->name)
@section('heading')
@if(Auth::user() && (in_array('EditRecipe',$allperms) || $recipe->user_id == Auth::user()->id))
<a href="{{ route('recipes.edit', $recipe->id) }}">{{$recipe->name}}</a>
@else
{{$recipe->name }}
@endif
@endsection
@section('content')
<div class="panel-body">
<div class="row">
<div class="col-md-3 text-center">Created By: {{$recipe->author}}</div>
<div class="col-md-3 text-center">Maintained By: {{$recipe->user->name}}</div>
<div class="col-md-3 text-center">Entered On: {{$recipe->date_entered->format('Y/m/d') }}</div>
<div class="col-md-3 text-center">Last Changed: {{$recipe->date_modified->format('Y/m/d') }}</div>
</div>
<div class="row">
<div class="col-sm-offset-3 col-sm-3 text-center">Servings: {{$recipe->servings}}</div>
<div class="col-sm-3 text-center">Serving Size: {{$recipe->serving_size}}</div>
</div>
<br />
<div class="row"><div class="panel-heading"><h1>Categories</h1></div></div>
<div class="row text-center">@foreach ($recipe->categories as $index => $category){{($index != 0 ? ", " : "").ucwords($category->name)}}@endforeach</div>
<br />
<div class="row"><div class="panel-heading"><h1>Description</h1></div></div>
<div class="row"><div class="col-sm-offset-2 col-lg-8">{!!$recipe->description!!}</div></div class="row">
<br />
<div class="row"><div class="panel-heading"><h1>Ingredients</h1></div></div>
@foreach ($recipe->ingredients as $index => $ingredient)
@if ($ingredient->alternative)
OR {{$ingredient->quantity}} {{$ingredient->measurement}} {{$ingredient->name}}
@else
@if($index != 0) </div> @endif
<div class="col-sm-offset-2 col-lg-4">{{$ingredient->quantity}} {{$ingredient->measurement}} {{$ingredient->name}}
@endif
@endforeach
@if(count($recipe->ingredients) > 0)
</div>
@endif
<br /><br />
<div class="row"><div class="panel-heading"><h1>Instructions</h1></div></div>
<div class="row"><div class="col-sm-offset-1 col-lg-10">{!!$recipe->instructions!!}</div>
</div>
@endsection

View file

@ -37,4 +37,5 @@ Route::group(['middleware' => 'permissions:SHARE'], function(){
Route::resource('users','UserController');
Route::resource('roles','RoleController');
Route::resource('recipes','RecipeController');
});