diff --git a/controllers/RecipesController.php b/controllers/RecipesController.php index 27cdc4bd..5457fac1 100644 --- a/controllers/RecipesController.php +++ b/controllers/RecipesController.php @@ -66,7 +66,9 @@ class RecipesController extends BaseController 'products' => $this->Database->products(), 'quantityunits' => $this->Database->quantity_units(), 'recipesFulfillment' => $this->RecipesService->GetRecipesFulfillment(), - 'recipesSumFulfillment' => $this->RecipesService->GetRecipesSumFulfillment() + 'recipesSumFulfillment' => $this->RecipesService->GetRecipesSumFulfillment(), + 'recipes' => $this->Database->recipes(), + 'recipeNestings' => $this->Database->recipes_nestings()->where('recipe_id', $recipeId) ]); } @@ -92,4 +94,25 @@ class RecipesController extends BaseController ]); } } + + public function RecipeIncludeEditForm(\Slim\Http\Request $request, \Slim\Http\Response $response, array $args) + { + if ($args['recipeIncludeId'] == 'new') + { + return $this->AppContainer->view->render($response, 'recipeincludeform', [ + 'mode' => 'create', + 'recipe' => $this->Database->recipes($args['recipeId']), + 'recipes' => $this->Database->recipes()->orderBy('name') + ]); + } + else + { + return $this->AppContainer->view->render($response, 'recipeincludeform', [ + 'mode' => 'edit', + 'recipe' => $this->Database->recipes($args['recipeId']), + 'recipeInclude' => $this->Database->recipes_nestings($args['recipeIncludeId']), + 'recipes' => $this->Database->recipes()->orderBy('name') + ]); + } + } } diff --git a/grocy.openapi.json b/grocy.openapi.json index 4ab5c640..1c116414 100644 --- a/grocy.openapi.json +++ b/grocy.openapi.json @@ -1675,6 +1675,7 @@ "shopping_list", "recipes", "recipes_pos", + "recipes_nestings", "tasks", "task_categories", "product_groups", diff --git a/public/viewjs/recipeform.js b/public/viewjs/recipeform.js index 37e53075..2e530176 100644 --- a/public/viewjs/recipeform.js +++ b/public/viewjs/recipeform.js @@ -35,15 +35,25 @@ var recipesPosTables = $('#recipes-pos-table').DataTable({ } }); -$("#search").on("keyup", function () -{ - var value = $(this).val(); - if (value === "all") +var recipesIncludesTables = $('#recipes-includes-table').DataTable({ + 'paginate': false, + 'order': [[1, 'asc']], + 'columnDefs': [ + { 'orderable': false, 'targets': 0 } + ], + 'language': JSON.parse(L('datatables_localization')), + 'scrollY': false, + 'colReorder': true, + 'stateSave': true, + 'stateSaveParams': function (settings, data) { - value = ""; - } + data.search.search = ""; - recipesPosTables.search(value).draw(); + data.columns.forEach(column => + { + column.search.search = ""; + }); + } }); Grocy.FrontendHelpers.ValidateForm('recipe-form'); @@ -108,6 +118,43 @@ $(document).on('click', '.recipe-pos-delete-button', function(e) }); }); +$(document).on('click', '.recipe-inlcude-delete-button', function(e) +{ + var objectName = $(e.currentTarget).attr('data-recipe-include-name'); + var objectId = $(e.currentTarget).attr('data-recipe-include-id'); + + bootbox.confirm({ + message: L('Are you sure to remove included recipe "#1"?', objectName), + buttons: { + confirm: { + label: L('Yes'), + className: 'btn-success' + }, + cancel: { + label: L('No'), + className: 'btn-danger' + } + }, + callback: function(result) + { + if (result === true) + { + Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), function() { }, function() { }); + Grocy.Api.Get('delete-object/recipes_nestings/' + objectId, + function(result) + { + window.location.href = U('/recipe/' + Grocy.EditObjectId); + }, + function(xhr) + { + console.error(xhr); + } + ); + } + } + }); +}); + $(document).on('click', '.recipe-pos-order-missing-button', function(e) { var productName = $(e.currentTarget).attr('data-product-name'); @@ -156,6 +203,22 @@ $(document).on('click', '.recipe-pos-edit-button', function (e) ); }); +$(document).on('click', '.recipe-include-edit-button', function (e) +{ + var id = $(e.currentTarget).attr('data-recipe-include-id'); + + Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), + function(result) + { + window.location.href = U('/recipe/' + Grocy.EditObjectId + '/included_recipe/' + id); + }, + function(xhr) + { + console.error(xhr); + } + ); +}); + $("#recipe-pos-add-button").on("click", function(e) { Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), @@ -170,6 +233,20 @@ $("#recipe-pos-add-button").on("click", function(e) ); }); +$("#recipe-include-add-button").on("click", function(e) +{ + Grocy.Api.Post('edit-object/recipes/' + Grocy.EditObjectId, $('#recipe-form').serializeJSON(), + function(result) + { + window.location.href = U('/recipe/' + Grocy.EditObjectId + '/included_recipe/new'); + }, + function(xhr) + { + console.error(xhr); + } + ); +}); + $('#description').summernote({ minHeight: '300px', lang: L('summernote_locale') diff --git a/public/viewjs/recipeincludeform.js b/public/viewjs/recipeincludeform.js new file mode 100644 index 00000000..8146a3e6 --- /dev/null +++ b/public/viewjs/recipeincludeform.js @@ -0,0 +1,62 @@ +$('#save-recipe-include-button').on('click', function(e) +{ + e.preventDefault(); + + var jsonData = $('#recipe-include-form').serializeJSON(); + jsonData.recipe_id = Grocy.EditObjectParentId; + if (Grocy.EditMode === 'create') + { + Grocy.Api.Post('add-object/recipes_nestings', jsonData, + function(result) + { + window.location.href = U('/recipe/' + Grocy.EditObjectParentId); + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } + else + { + Grocy.Api.Post('edit-object/recipes_nestings/' + Grocy.EditObjectId, jsonData, + function(result) + { + window.location.href = U('/recipe/' + Grocy.EditObjectParentId); + }, + function(xhr) + { + Grocy.FrontendHelpers.ShowGenericError('Error while saving, probably this item already exists', xhr.response) + } + ); + } +}); + +Grocy.FrontendHelpers.ValidateForm('recipe-include-form'); + +$('#recipe-include-form input').keyup(function(event) +{ + Grocy.FrontendHelpers.ValidateForm('recipe-include-form'); +}); + +$('#recipe-include-form select').change(function(event) +{ + Grocy.FrontendHelpers.ValidateForm('recipe-include-form'); +}); + +$('#recipe-include-form input').keydown(function(event) +{ + if (event.keyCode === 13) //Enter + { + event.preventDefault(); + + if (document.getElementById('recipe-include-form').checkValidity() === false) //There is at least one validation error + { + return false; + } + else + { + $('#save-include-include-button').click(); + } + } +}); diff --git a/routes.php b/routes.php index 3014f735..abe93f6d 100644 --- a/routes.php +++ b/routes.php @@ -40,6 +40,7 @@ $app->group('', function() $this->get('/recipes', '\Grocy\Controllers\RecipesController:Overview'); $this->get('/recipe/{recipeId}', '\Grocy\Controllers\RecipesController:RecipeEditForm'); $this->get('/recipe/{recipeId}/pos/{recipePosId}', '\Grocy\Controllers\RecipesController:RecipePosEditForm'); + $this->get('/recipe/{recipeId}/included_recipe/{recipeIncludeId}', '\Grocy\Controllers\RecipesController:RecipeIncludeEditForm'); // Chore routes $this->get('/choresoverview', '\Grocy\Controllers\ChoresController:Overview'); diff --git a/views/recipeform.blade.php b/views/recipeform.blade.php index feddb61e..c7747244 100644 --- a/views/recipeform.blade.php +++ b/views/recipeform.blade.php @@ -51,53 +51,95 @@
-

- {{ $L('Ingredients list') }} - - {{ $L('Add') }} - -

- - - - - - - - - - - @if($mode == "edit") - @foreach($recipePositions as $recipePosition) - - - - - - - @endforeach - @endif - -
#{{ $L('Product') }}{{ $L('Amount') }}{{ $L('Note') }}
- - - - - - - - - - - {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }} - - {{ $recipePosition->amount }} {{ Pluralize($recipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural) }} - @if(FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->need_fulfilled == 1) {{ $L('Enough in stock') }} @else {{ $L('Not enough in stock, #1 missing, #2 already on shopping list', FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->missing_amount, FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->amount_on_shopping_list) }} @endif - - - - -
+
+
+

+ {{ $L('Ingredients list') }} + + {{ $L('Add') }} + +

+ + + + + + + + + + + @if($mode == "edit") + @foreach($recipePositions as $recipePosition) + + + + + + + @endforeach + @endif + +
#{{ $L('Product') }}{{ $L('Amount') }}{{ $L('Note') }}
+ + + + + + + + + + + {{ FindObjectInArrayByPropertyValue($products, 'id', $recipePosition->product_id)->name }} + + {{ $recipePosition->amount }} {{ Pluralize($recipePosition->amount, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name, FindObjectInArrayByPropertyValue($quantityunits, 'id', $recipePosition->qu_id)->name_plural) }} + @if(FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->need_fulfilled == 1) {{ $L('Enough in stock') }} @else {{ $L('Not enough in stock, #1 missing, #2 already on shopping list', FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->missing_amount, FindObjectInArrayByPropertyValue($recipesFulfillment, 'recipe_pos_id', $recipePosition->id)->amount_on_shopping_list) }} @endif + + + + +
+
+
+ +
+
+

+ {{ $L('Included recipes') }} + + {{ $L('Add') }} + +

+ + + + + + + + + @if($mode == "edit") + @foreach($recipeNestings as $recipeNesting) + + + + + @endforeach + @endif + +
#{{ $L('Recipe') }}
+ + + + + + + + {{ FindObjectInArrayByPropertyValue($recipes, 'id', $recipeNesting->recipe_id)->name }} +
+
+
@stop diff --git a/views/recipeincludeform.blade.php b/views/recipeincludeform.blade.php new file mode 100644 index 00000000..c1c12325 --- /dev/null +++ b/views/recipeincludeform.blade.php @@ -0,0 +1,44 @@ +@extends('layout.default') + +@if($mode == 'edit') + @section('title', $L('Edit included recipe')) +@else + @section('title', $L('Add included recipe')) +@endif + +@section('viewJsName', 'recipeincludeform') + +@section('content') +
+
+

@yield('title')

+

{{ $L('Recipe') }} {{ $recipe->name }}

+ + + + @if($mode == 'edit') + + @endif + +
+ +
+ + +
{{ $L('A recipe is required') }}
+
+ + + +
+
+
+@stop