Added a "recipe gallery" view (closes #147)

This commit is contained in:
Bernd Bestel
2019-03-05 17:59:33 +01:00
parent 8504429f5f
commit 816eb03147
4 changed files with 116 additions and 44 deletions

View File

@@ -341,5 +341,7 @@ return array(
'This is useful e.g. for flour in jars - on purchase/consume/inventory you always weigh the whole jar, the amount to be posted is then automatically calculated based on what is in stock and the tare weight defined below' => 'This is useful e.g. for flour in jars - on purchase/consume/inventory you always weigh the whole jar, the amount to be posted is then automatically calculated based on what is in stock and the tare weight defined below', 'This is useful e.g. for flour in jars - on purchase/consume/inventory you always weigh the whole jar, the amount to be posted is then automatically calculated based on what is in stock and the tare weight defined below' => 'This is useful e.g. for flour in jars - on purchase/consume/inventory you always weigh the whole jar, the amount to be posted is then automatically calculated based on what is in stock and the tare weight defined below',
'Tare weight' => 'Tare weight', 'Tare weight' => 'Tare weight',
'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated' => 'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated', 'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated' => 'Tare weight handling enabled - please weigh the whole container, the amount to be posted will be automatically calculcated',
'You have to select a location' => 'You have to select a location' 'You have to select a location' => 'You have to select a location',
'List' => 'List',
'Gallery' => 'Gallery'
); );

View File

@@ -26,12 +26,29 @@
$('#recipes-table tbody').removeClass("d-none"); $('#recipes-table tbody').removeClass("d-none");
recipesTables.columns.adjust().draw(); recipesTables.columns.adjust().draw();
var rowSelect = GetUriParam("row"); if ((typeof tab !== "undefined" && tab === "gallery") || window.localStorage.getItem("recipes_last_tab_id") == "gallery-tab")
if (typeof rowSelect !== "undefined")
{ {
recipesTables.row(rowSelect).select(); $(".nav-tabs a[href='#gallery']").tab("show");
} }
var recipe = GetUriParam("recipe");
if (typeof recipe !== "undefined")
{
$("#recipes-table tr").removeClass("selected");
var rowId = "#recipe-row-" + recipe;
$(rowId).addClass("selected")
var cardId = "#recipe-card-" + recipe;
$(cardId).addClass("bg-primary").addClass("text-white");
$(cardId)[0].scrollIntoView();
}
$("a[data-toggle='tab']").on("shown.bs.tab", function(e)
{
var tabId = $(e.target).attr("id");
window.localStorage.setItem("recipes_last_tab_id", tabId);
});
$("#search").on("keyup", function() $("#search").on("keyup", function()
{ {
var value = $(this).val(); var value = $(this).val();
@@ -169,10 +186,17 @@ recipesTables.on('select', function(e, dt, type, indexes)
if (type === 'row') if (type === 'row')
{ {
var selectedRecipeId = $(recipesTables.row(indexes[0]).node()).data("recipe-id"); var selectedRecipeId = $(recipesTables.row(indexes[0]).node()).data("recipe-id");
window.location.href = U('/recipes?recipe=' + selectedRecipeId.toString() + "&row=" + indexes[0].toString()); window.location.href = U('/recipes?recipe=' + selectedRecipeId.toString());
} }
}); });
$(".recipe-gallery-item").on("click", function(e)
{
e.preventDefault();
window.location.href = U('/recipes?tab=gallery&recipe=' + $(this).data("recipe-id"));
});
$("#selectedRecipeToggleFullscreenButton").on('click', function(e) $("#selectedRecipeToggleFullscreenButton").on('click', function(e)
{ {
e.preventDefault(); e.preventDefault();

View File

@@ -71,12 +71,12 @@ class DemoDataGeneratorService extends BaseService
INSERT INTO shopping_list (product_id, amount) VALUES (20, 1); INSERT INTO shopping_list (product_id, amount) VALUES (20, 1);
INSERT INTO shopping_list (product_id, amount) VALUES (17, 1); INSERT INTO shopping_list (product_id, amount) VALUES (17, 1);
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Pizza')}', '{$loremIpsumWithHtmlFormattings}'); --1 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Pizza')}', '{$loremIpsumWithHtmlFormattings}', 'pizza.jpg'); --1
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}'); --2 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}', 'spaghetti.jpg'); --2
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}'); --3 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}', 'sandwiches.jpg'); --3
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')}', '{$loremIpsumWithHtmlFormattings}'); --4 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')}', '{$loremIpsumWithHtmlFormattings}', 'pancakes.jpg'); --4
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}'); --5 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}', 'chocolate_sauce.jpg'); --5
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')} / {$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}'); --6 INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')} / {$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}', 'pancakes_chocolate_sauce.jpg'); --6
INSERT INTO recipes_pos (recipe_id, product_id, amount, ingredient_group) VALUES (1, 16, 1, '{$localizationService->LocalizeForSqlString('Bottom')}'); INSERT INTO recipes_pos (recipe_id, product_id, amount, ingredient_group) VALUES (1, 16, 1, '{$localizationService->LocalizeForSqlString('Bottom')}');
INSERT INTO recipes_pos (recipe_id, product_id, amount, ingredient_group) VALUES (1, 17, 1, '{$localizationService->LocalizeForSqlString('Topping')}'); INSERT INTO recipes_pos (recipe_id, product_id, amount, ingredient_group) VALUES (1, 17, 1, '{$localizationService->LocalizeForSqlString('Topping')}');
@@ -225,9 +225,11 @@ class DemoDataGeneratorService extends BaseService
// Download demo storage data // Download demo storage data
$productPicturesFolder = GROCY_DATAPATH . '/storage/productpictures'; $productPicturesFolder = GROCY_DATAPATH . '/storage/productpictures';
$equipmentManualsFolder = GROCY_DATAPATH . '/storage/equipmentmanuals'; $equipmentManualsFolder = GROCY_DATAPATH . '/storage/equipmentmanuals';
$recipePicturesFolder = GROCY_DATAPATH . '/storage/recipepictures';
mkdir(GROCY_DATAPATH . '/storage'); mkdir(GROCY_DATAPATH . '/storage');
mkdir(GROCY_DATAPATH . '/storage/productpictures'); mkdir($productPicturesFolder);
mkdir(GROCY_DATAPATH . '/storage/equipmentmanuals'); mkdir($equipmentManualsFolder);
mkdir($recipePicturesFolder);
$sslOptions = array( $sslOptions = array(
'ssl' => array( 'ssl' => array(
'verify_peer' => false, 'verify_peer' => false,
@@ -240,6 +242,12 @@ class DemoDataGeneratorService extends BaseService
file_put_contents("$productPicturesFolder/paprika.jpg", file_get_contents('https://releases.grocy.info/demoresources/paprika.jpg', false, stream_context_create($sslOptions))); file_put_contents("$productPicturesFolder/paprika.jpg", file_get_contents('https://releases.grocy.info/demoresources/paprika.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$productPicturesFolder/tomato.jpg", file_get_contents('https://releases.grocy.info/demoresources/tomato.jpg', false, stream_context_create($sslOptions))); file_put_contents("$productPicturesFolder/tomato.jpg", file_get_contents('https://releases.grocy.info/demoresources/tomato.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$equipmentManualsFolder/loremipsum.pdf", file_get_contents('https://releases.grocy.info/demoresources/loremipsum.pdf', false, stream_context_create($sslOptions))); file_put_contents("$equipmentManualsFolder/loremipsum.pdf", file_get_contents('https://releases.grocy.info/demoresources/loremipsum.pdf', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/pizza.jpg", file_get_contents('https://releases.grocy.info/demoresources/pizza.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/sandwiches.jpg", file_get_contents('https://releases.grocy.info/demoresources/sandwiches.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/pancakes.jpg", file_get_contents('https://releases.grocy.info/demoresources/pancakes.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/spaghetti.jpg", file_get_contents('https://releases.grocy.info/demoresources/spaghetti.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/chocolate_sauce.jpg", file_get_contents('https://releases.grocy.info/demoresources/chocolate_sauce.jpg', false, stream_context_create($sslOptions)));
file_put_contents("$recipePicturesFolder/pancakes_chocolate_sauce.jpg", file_get_contents('https://releases.grocy.info/demoresources/pancakes_chocolate_sauce.jpg', false, stream_context_create($sslOptions)));
} }
} }

View File

@@ -18,6 +18,18 @@
<label for="search">{{ $L('Search') }}</label> <i class="fas fa-search"></i> <label for="search">{{ $L('Search') }}</label> <i class="fas fa-search"></i>
<input type="text" class="form-control" id="search"> <input type="text" class="form-control" id="search">
<ul class="nav nav-tabs mt-3">
<li class="nav-item">
<a class="nav-link active" id="list-tab" data-toggle="tab" href="#list">{{ $L('List') }}</a>
</li>
<li class="nav-item">
<a class="nav-link" id="gallery-tab" data-toggle="tab" href="#gallery">{{ $L('Gallery') }}</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane show active" id="list">
<table id="recipes-table" class="table table-striped dt-responsive"> <table id="recipes-table" class="table table-striped dt-responsive">
<thead> <thead>
<tr> <tr>
@@ -29,7 +41,7 @@
</thead> </thead>
<tbody class="d-none"> <tbody class="d-none">
@foreach($recipes as $recipe) @foreach($recipes as $recipe)
<tr data-recipe-id="{{ $recipe->id }}"> <tr id="recipe-row-{{ $recipe->id }}" data-recipe-id="{{ $recipe->id }}">
<td> <td>
{{ $recipe->name }} {{ $recipe->name }}
</td> </td>
@@ -49,6 +61,32 @@
</table> </table>
</div> </div>
<div class="tab-pane show" id="gallery">
<div class="row no-gutters">
@foreach($recipes as $recipe)
<div class="col-6">
<a class="discrete-link recipe-gallery-item" data-recipe-id="{{ $recipe->id }}" href="#">
<div id="recipe-card-{{ $recipe->id }}" class="card border-white mb-0">
@if(!empty($recipe->picture_file_name))
<img src="{{ $U('/api/files/recipepictures/' . base64_encode($recipe->picture_file_name)) }}" class="img-fluid">
@endif
<div class="card-body text-center">
<h5 class="card-title mb-1">{{ $recipe->name }}</h5>
<p class="card-text">
@if(FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->need_fulfilled == 1)<i class="fas fa-check text-success"></i>@elseif(FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1)<i class="fas fa-exclamation text-warning"></i>@else<i class="fas fa-times text-danger"></i>@endif
<span class="timeago-contextual">@if(FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->need_fulfilled == 1){{ $L('Enough in stock') }}@elseif(FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->need_fulfilled_with_shopping_list == 1){{ $L('Not enough in stock, #1 ingredients missing but already on the shopping list', FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->missing_products_count) }}@else{{ $L('Not enough in stock, #1 ingredients missing', FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->missing_products_count) }}@endif</span>
</p>
</div>
</div>
</a>
</div>
@endforeach
</div>
</div>
</div>
</div>
@if($selectedRecipe !== null) @if($selectedRecipe !== null)
<div class="col-xs-12 col-md-6"> <div class="col-xs-12 col-md-6">
<div id="selectedRecipeCard" class="card"> <div id="selectedRecipeCard" class="card">
@@ -88,7 +126,7 @@
<span class="small text-muted">{{ $L('Based on the prices of the last purchase per product') }}</span> <span class="small text-muted">{{ $L('Based on the prices of the last purchase per product') }}</span>
</label> </label>
<p class="font-weight-bold font-italic"> <p class="font-weight-bold font-italic">
<span class="locale-number-format" data-format="currency">{{ $totalRecipeCosts }}</span> {{ GROCY_CURRENCY }} <span class="locale-number-format" data-format="currency">{{ $totalRecipeCosts }}</span>
</p> </p>
</div> </div>
</div> </div>
@@ -101,7 +139,7 @@
</div> </div>
@if(!empty($selectedRecipeSubRecipe->picture_file_name)) @if(!empty($selectedRecipeSubRecipe->picture_file_name))
<p><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipeSubRecipe->picture_file_name)) }}" class="img-fluid"></p> <p class="w-75 mx-auto"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipeSubRecipe->picture_file_name)) }}" class="img-fluid img-thumbnail"></p>
@endif @endif
@php $selectedRecipeSubRecipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($selectedRecipeSubRecipesPositions, 'recipe_id', $selectedRecipeSubRecipe->id); @endphp @php $selectedRecipeSubRecipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($selectedRecipeSubRecipesPositions, 'recipe_id', $selectedRecipeSubRecipe->id); @endphp
@@ -137,7 +175,7 @@
<!-- Selected recipe --> <!-- Selected recipe -->
@if(!empty($selectedRecipe->picture_file_name)) @if(!empty($selectedRecipe->picture_file_name))
<p><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name)) }}" class="img-fluid"></p> <p class="w-75 mx-auto"><img src="{{ $U('/api/files/recipepictures/' . base64_encode($selectedRecipe->picture_file_name)) }}" class="img-fluid img-thumbnail"></p>
@endif @endif
@if($selectedRecipePositions->count() > 0) @if($selectedRecipePositions->count() > 0)