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',
'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',
'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");
recipesTables.columns.adjust().draw();
var rowSelect = GetUriParam("row");
if (typeof rowSelect !== "undefined")
if ((typeof tab !== "undefined" && tab === "gallery") || window.localStorage.getItem("recipes_last_tab_id") == "gallery-tab")
{
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()
{
var value = $(this).val();
@@ -169,10 +186,17 @@ recipesTables.on('select', function(e, dt, type, indexes)
if (type === 'row')
{
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)
{
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 (17, 1);
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Pizza')}', '{$loremIpsumWithHtmlFormattings}'); --1
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}'); --2
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}'); --3
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')}', '{$loremIpsumWithHtmlFormattings}'); --4
INSERT INTO recipes (name, description) VALUES ('{$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}'); --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('Pizza')}', '{$loremIpsumWithHtmlFormattings}', 'pizza.jpg'); --1
INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Spaghetti bolognese')}', '{$loremIpsumWithHtmlFormattings}', 'spaghetti.jpg'); --2
INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Sandwiches')}', '{$loremIpsumWithHtmlFormattings}', 'sandwiches.jpg'); --3
INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Pancakes')}', '{$loremIpsumWithHtmlFormattings}', 'pancakes.jpg'); --4
INSERT INTO recipes (name, description, picture_file_name) VALUES ('{$localizationService->LocalizeForSqlString('Chocolate sauce')}', '{$loremIpsumWithHtmlFormattings}', 'chocolate_sauce.jpg'); --5
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, 17, 1, '{$localizationService->LocalizeForSqlString('Topping')}');
@@ -225,9 +225,11 @@ class DemoDataGeneratorService extends BaseService
// Download demo storage data
$productPicturesFolder = GROCY_DATAPATH . '/storage/productpictures';
$equipmentManualsFolder = GROCY_DATAPATH . '/storage/equipmentmanuals';
$recipePicturesFolder = GROCY_DATAPATH . '/storage/recipepictures';
mkdir(GROCY_DATAPATH . '/storage');
mkdir(GROCY_DATAPATH . '/storage/productpictures');
mkdir(GROCY_DATAPATH . '/storage/equipmentmanuals');
mkdir($productPicturesFolder);
mkdir($equipmentManualsFolder);
mkdir($recipePicturesFolder);
$sslOptions = array(
'ssl' => array(
'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/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("$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,35 +18,73 @@
<label for="search">{{ $L('Search') }}</label> <i class="fas fa-search"></i>
<input type="text" class="form-control" id="search">
<table id="recipes-table" class="table table-striped dt-responsive">
<thead>
<tr>
<th>{{ $L('Name') }}</th>
<th class="fit-content text-right">{{ $L('Servings') }}</th>
<th>{{ $L('Requirements fulfilled') }}</th>
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
</tr>
</thead>
<tbody class="d-none">
@foreach($recipes as $recipe)
<tr data-recipe-id="{{ $recipe->id }}">
<td>
{{ $recipe->name }}
</td>
<td class="fit-content text-right">
{{ $recipe->desired_servings }}
</td>
<td>
@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>
</td>
<td class="d-none">
{{ FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->missing_products_count }}
</td>
</tr>
<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">
<thead>
<tr>
<th>{{ $L('Name') }}</th>
<th class="fit-content text-right">{{ $L('Servings') }}</th>
<th>{{ $L('Requirements fulfilled') }}</th>
<th class="d-none">Hidden status for sorting of "Requirements fulfilled" column</th>
</tr>
</thead>
<tbody class="d-none">
@foreach($recipes as $recipe)
<tr id="recipe-row-{{ $recipe->id }}" data-recipe-id="{{ $recipe->id }}">
<td>
{{ $recipe->name }}
</td>
<td class="fit-content text-right">
{{ $recipe->desired_servings }}
</td>
<td>
@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>
</td>
<td class="d-none">
{{ FindObjectInArrayByPropertyValue($recipesSumFulfillment, 'recipe_id', $recipe->id)->missing_products_count }}
</td>
</tr>
@endforeach
</tbody>
</table>
</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
</tbody>
</table>
</div>
</div>
</div>
</div>
@if($selectedRecipe !== null)
@@ -88,7 +126,7 @@
<span class="small text-muted">{{ $L('Based on the prices of the last purchase per product') }}</span>
</label>
<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>
</div>
</div>
@@ -101,7 +139,7 @@
</div>
@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
@php $selectedRecipeSubRecipePositionsFiltered = FindAllObjectsInArrayByPropertyValue($selectedRecipeSubRecipesPositions, 'recipe_id', $selectedRecipeSubRecipe->id); @endphp
@@ -137,7 +175,7 @@
<!-- Selected recipe -->
@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
@if($selectedRecipePositions->count() > 0)