diff --git a/apps/Index/Controllers/HomepageController.php b/apps/Index/Controllers/HomepageController.php index 2114f69..eb9111d 100644 --- a/apps/Index/Controllers/HomepageController.php +++ b/apps/Index/Controllers/HomepageController.php @@ -2,9 +2,40 @@ namespace Lycoreco\Apps\Index\Controllers; +use Lycoreco\Apps\Recipes\Models\CategoryModel; +use Lycoreco\Apps\Recipes\Models\RecipeModel; +use Lycoreco\Apps\Recipes\Models\RecipeUserMenu; use Lycoreco\Includes\BaseController; +require_once(INCLUDES_PATH . '/Const/recipes.php'); + class HomepageController extends BaseController { protected $template_name = APPS_PATH . '/Index/Templates/index.php'; + + public function get_context_data() { + $context = parent::get_context_data(); + + $context['latest_recipes'] = RecipeModel::filter(array( + [ + 'name' => 'obj.status', + 'type' => '=', + 'value' => 'publish' + ]), + ['-obj.created_at'], + 3 + ); + $context['categories'] = CategoryModel::filter(); + $dayNumber = date("w"); + $dayofweek = DAYS_OF_WEEK[$dayNumber]; + + if(CURRENT_USER) { + $context['usermenu_recipe_prefetch'] = RecipeUserMenu::get_prefetch_recipes(CURRENT_USER, $dayofweek); + } + else { + $context['usermenu_recipe_prefetch'] = [ ]; + } + + return $context; + } } diff --git a/apps/Index/Templates/index.php b/apps/Index/Templates/index.php index 1a6c246..9c03da4 100644 --- a/apps/Index/Templates/index.php +++ b/apps/Index/Templates/index.php @@ -1,4 +1,6 @@ -
+ +
- +
- Recipe 1 + Recipe 1
-

Spaghetti Bolognese

-

GreenDavid004

-
-
-
-
- -
- Recipe 1 - -
-
-

Spaghetti Bolognese

-

GreenDavid004

-
-
-
-
- -
- Recipe 1 - -
-
-

Spaghetti Bolognese

-

GreenDavid004

+

field_title ?>

+

author_username ?>

+
@@ -86,87 +67,14 @@
+ - - - - - - - - +
@@ -278,137 +186,18 @@
+
-

Your Menu for Monday

+

Your Menu for

- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
- -
- meal-img -
-
-
-

Goulash

- 120mins to make -
-
-
    -
  • Ground beef
  • -
  • Tomato sauce
  • -
  • Onion
  • -
  • Macaroni
  • -
  • Garlic
  • -
  • Cheese
  • -
-
-
-
+
+ diff --git a/apps/Recipes/Controllers/CatalogController.php b/apps/Recipes/Controllers/CatalogController.php index 5a63e84..c12c6fd 100644 --- a/apps/Recipes/Controllers/CatalogController.php +++ b/apps/Recipes/Controllers/CatalogController.php @@ -9,7 +9,7 @@ use Lycoreco\Apps\Recipes\Models\{ }; use Lycoreco\Includes\BaseController; -define('CATALOG_MAX_RECIPES', 20); +define('CATALOG_MAX_RECIPES', 10); class CatalogController extends BaseController { @@ -45,10 +45,12 @@ class CatalogController extends BaseController ); } + $context['recipes_count'] = RecipeModel::count($fields); $context['recipes'] = RecipeModel::filter( $fields, ['-obj.created_at'], - CATALOG_MAX_RECIPES + CATALOG_MAX_RECIPES, + offset: calc_page_offset(CATALOG_MAX_RECIPES, $context['page']) ); return $context; diff --git a/apps/Recipes/Controllers/DailyMealsController.php b/apps/Recipes/Controllers/DailyMealsController.php index c50320f..dad7262 100644 --- a/apps/Recipes/Controllers/DailyMealsController.php +++ b/apps/Recipes/Controllers/DailyMealsController.php @@ -2,12 +2,26 @@ namespace Lycoreco\Apps\Recipes\Controllers; - +use Lycoreco\Apps\Recipes\Models\RecipeUserMenu; use Lycoreco\Includes\BaseController; - +require_once(INCLUDES_PATH . '/Const/recipes.php'); class DailyMealsController extends BaseController { protected $template_name = APPS_PATH . '/Recipes/Templates/daily-meals.php'; + + protected $allow_role = 'user'; + + function get_context_data() { + $context = parent::get_context_data(); + + $context['weeks'] = array(); + + foreach (DAYS_OF_WEEK as $week) { + $context['weeks'][$week] = RecipeUserMenu::get_prefetch_recipes(CURRENT_USER, $week); + } + + return $context; + } } \ No newline at end of file diff --git a/apps/Recipes/Controllers/FavoritesController.php b/apps/Recipes/Controllers/FavoritesController.php index ab406cc..c5047d6 100644 --- a/apps/Recipes/Controllers/FavoritesController.php +++ b/apps/Recipes/Controllers/FavoritesController.php @@ -2,24 +2,48 @@ namespace Lycoreco\Apps\Recipes\Controllers; +use Lycoreco\Apps\Recipes\Models\FavoriteModel; use Lycoreco\Apps\Recipes\Models\RecipeModel; use Lycoreco\Includes\BaseController; -define('FAVORITES_MAX_RECIPES', 20); +define('FAVORITES_MAX_RECIPES', 500); class FavoritesController extends BaseController { protected $template_name = APPS_PATH . '/Recipes/Templates/favorites.php'; + protected $allow_role = 'user'; public function get_context_data() { $context = parent::get_context_data(); + + $favorite_recipes = FavoriteModel::filter(array( + [ + 'name' => 'obj.user_id', + 'type' => '=', + 'value' => CURRENT_USER->get_id() + ] + )); + $fav_ids = array_map(function($recipe) { + return $recipe->field_recipe_id; + }, $favorite_recipes); - $context['recipes'] = RecipeModel::filter( - [], - ['-obj.created_at'], - FAVORITES_MAX_RECIPES - ); + if(!empty($fav_ids)) { + $context['recipes'] = RecipeModel::filter( + array( + [ + 'name' => 'obj.id', + 'type' => 'IN', + 'value' => $fav_ids + ] + ), + ['-obj.created_at'], + FAVORITES_MAX_RECIPES + ); + } + else { + $context['recipes'] = []; + } return $context; } diff --git a/apps/Recipes/Models/RecipeModel.php b/apps/Recipes/Models/RecipeModel.php index 1358a09..561a84e 100644 --- a/apps/Recipes/Models/RecipeModel.php +++ b/apps/Recipes/Models/RecipeModel.php @@ -16,7 +16,9 @@ class RecipeModel extends BaseModel public $field_created_at; public $category_name; + public $author_username; public $is_in_favorite = 0; + public $in_usermenu = false; const STATUS = [['publish', 'Publish'], ['pending', 'Pending']]; @@ -30,6 +32,12 @@ class RecipeModel extends BaseModel ], 'join_table' => 'categories tb1 ON tb1.id = obj.category_id' ], + [ + 'field' => [ + 'us.username AS author_username' + ], + 'join_table' => 'users us ON us.id = obj.author_id' + ], [ 'field' => [ @@ -63,6 +71,16 @@ class RecipeModel extends BaseModel ] )); } + if(CURRENT_USER) { + $add_fields = array_merge($add_fields, array( + [ + "field" => [ + "MAX(m.dayofweek) AS in_usermenu" + ], + "join_table" => "recipe_usermenu m ON m.recipe_id = obj.id AND m.user_id = " . CURRENT_USER->get_id() + ] + )); + } return $add_fields; } diff --git a/apps/Recipes/Models/RecipeUserMenu.php b/apps/Recipes/Models/RecipeUserMenu.php index 4de708d..4141b05 100644 --- a/apps/Recipes/Models/RecipeUserMenu.php +++ b/apps/Recipes/Models/RecipeUserMenu.php @@ -2,6 +2,7 @@ namespace Lycoreco\Apps\Recipes\Models; +use Lycoreco\Apps\Users\Models\UserModel; use Lycoreco\Includes\Model\BaseModel; class RecipeUserMenu extends BaseModel @@ -39,7 +40,7 @@ class RecipeUserMenu extends BaseModel { require_once INCLUDES_PATH . '/Const/recipes.php'; - if(!in_array($this->field_dayofweek, DAYS_OF_WEEK)) + if (!in_array($this->field_dayofweek, DAYS_OF_WEEK)) return ['Day of Week is not valid']; $recipe = RecipeModel::get(array( @@ -49,9 +50,44 @@ class RecipeUserMenu extends BaseModel 'value' => $this->field_recipe_id ] )); - if(!$recipe) + if (!$recipe) return ['Recipe does not exist']; return true; } -} \ No newline at end of file + + public static function get_prefetch_recipes(UserModel $user, string $week) { + $usermenus = RecipeUserMenu::filter(array( + [ + 'name' => 'obj.user_id', + 'type' => '=', + 'value' => $user->get_id(), + ], + [ + 'name' => 'obj.dayofweek', + 'type' => '=', + 'value' => $week + ] + ), count: 100); + + if(empty($usermenus)) + return []; + + $usermenu_ids = array_map(function($usermenu) { + return $usermenu->field_recipe_id; + }, $usermenus); + + + $recipes = RecipeModel::filter(array( + [ + 'name' => 'obj.id', + 'type' => 'IN', + 'value' => $usermenu_ids + ] + )); + + $prefetch_recipes_ings = prefetch_related($recipes, 'Recipes:IngredientInRecipeModel', 'recipe_id'); + + return $prefetch_recipes_ings; + } +} diff --git a/apps/Recipes/Templates/catalog.php b/apps/Recipes/Templates/catalog.php index 2c2d6ec..b08f088 100644 --- a/apps/Recipes/Templates/catalog.php +++ b/apps/Recipes/Templates/catalog.php @@ -13,12 +13,15 @@ the_header( ?>
-
- +
+
+ +
+
diff --git a/apps/Recipes/Templates/components/recipe-ings-item.php b/apps/Recipes/Templates/components/recipe-ings-item.php new file mode 100644 index 0000000..b9eb960 --- /dev/null +++ b/apps/Recipes/Templates/components/recipe-ings-item.php @@ -0,0 +1,18 @@ + +
+ meal-img +
+
+
+

field_title ?>

+ field_estimated_time ?>mins to make +
+
+
    + +
  • ingredient_name ?>
  • + +
+
+
+
\ No newline at end of file diff --git a/apps/Recipes/Templates/daily-meals.php b/apps/Recipes/Templates/daily-meals.php index 33ac0e9..56d4e46 100644 --- a/apps/Recipes/Templates/daily-meals.php +++ b/apps/Recipes/Templates/daily-meals.php @@ -1,4 +1,5 @@ diff --git a/apps/Recipes/Templates/single.php b/apps/Recipes/Templates/single.php index b3617f0..90395eb 100644 --- a/apps/Recipes/Templates/single.php +++ b/apps/Recipes/Templates/single.php @@ -12,6 +12,7 @@ the_header( ?> +
diff --git a/apps/Recipes/components.php b/apps/Recipes/components.php index c0c76ef..a56faab 100644 --- a/apps/Recipes/components.php +++ b/apps/Recipes/components.php @@ -5,4 +5,8 @@ use Lycoreco\Apps\Recipes\Models\RecipeModel; function the_product_item(RecipeModel $recipe) { include APPS_PATH . '/Recipes/Templates/components/catalog-item.php'; +} +function the_product_recipes_item(RecipeModel $recipe, array $ingredients) +{ + include APPS_PATH . '/Recipes/Templates/components/recipe-ings-item.php'; } \ No newline at end of file diff --git a/assets/js/single.js b/assets/js/single.js index fd96f5b..c8754d7 100644 --- a/assets/js/single.js +++ b/assets/js/single.js @@ -15,13 +15,41 @@ document.addEventListener('click', (e) => { const options = document.querySelectorAll('.dropdown-item'); +const inUsermenu = document.getElementById('in-usermenu').textContent; +if (inUsermenu) { + options.forEach(option => { + if (option.getAttribute('data-value') === inUsermenu && option.getAttribute('data-value') !== 'remove') { + option.classList.add('dropdown-selected'); + toggleBtn.textContent = option.textContent; + } + }); +} options.forEach(option => { - option.addEventListener('click', () => { + option.addEventListener('click', async (e) => { const selectedValue = option.getAttribute('data-value'); options.forEach(opt => opt.classList.remove('dropdown-selected')); + const formData = new FormData(); + formData.append('action', 'usermenu'); + formData.append('recipe_id', recipeId); + formData.append('dayofweek', selectedValue); + + const response = await fetch('/ajax', { + method: 'POST', + body: formData + }); + + const json = await response.json(); + + if (!response.ok) { + const message = json.error; + showToastify(message, 'error'); + return; + } + + if (selectedValue === 'remove') { toggleBtn.textContent = 'Add to list'; } else { @@ -31,7 +59,7 @@ options.forEach(option => { dropdown.classList.add('hidden'); - alert(`You selected: ${selectedValue}`); + showToastify(json.success, 'success'); }); }); @@ -42,20 +70,20 @@ const qrPopup = document.querySelector(".qr-popup"); const overlay = document.getElementById('overlay'); qrBtn.addEventListener("click", () => { - + qrPopup.classList.toggle("hidden") overlay.classList.toggle("hidden") - + qrContainer.innerHTML = ""; - + new QRCode(qrContainer, { text: window.location.href, width: 200, height: 200 }); - + setTimeout(() => { const qrImg = qrContainer.querySelector("img"); if (qrImg) { @@ -64,8 +92,8 @@ qrBtn.addEventListener("click", () => { }, 500); }); -document.addEventListener('click', (e) =>{ - if(!qrPopup.contains(e.target) && !qrBtn.contains(e.target)){ +document.addEventListener('click', (e) => { + if (!qrPopup.contains(e.target) && !qrBtn.contains(e.target)) { qrPopup.classList.add("hidden"); overlay.classList.add("hidden"); } @@ -85,7 +113,7 @@ favoriteBtn.addEventListener('click', async (e) => { formData.append('type', type); favoriteBtn.disabled = true; - const response = await fetch('/ajax', { + const response = await fetch('/ajax', { method: 'POST', body: formData }); @@ -93,20 +121,20 @@ favoriteBtn.addEventListener('click', async (e) => { const json = await response.json(); - if(!response.ok) { + if (!response.ok) { const message = json.error; showToastify(message, 'error'); return; } favoriteBtn.classList.toggle('active'); - if(type == 'add') { + if (type == 'add') { favoriteIcon.classList.remove('fa-regular'); favoriteIcon.classList.add('fa-solid'); } else { favoriteIcon.classList.add('fa-regular'); favoriteIcon.classList.remove('fa-solid'); } - + showToastify(json.success, 'success'); }); \ No newline at end of file diff --git a/functions.php b/functions.php index 1c36911..0159aa7 100644 --- a/functions.php +++ b/functions.php @@ -133,13 +133,13 @@ function the_pagination(int $count, int $elem_per_page, int $current_page) continue; $GET['page'] = $i; ?> -
  • +
  • 0 && $current_page <= $total_pages): ?>
  • -
    +
  • @@ -147,7 +147,7 @@ function the_pagination(int $count, int $elem_per_page, int $current_page) -
  • +
  • diff --git a/includes/Const/recipes.php b/includes/Const/recipes.php index 8b971ca..19b83d5 100644 --- a/includes/Const/recipes.php +++ b/includes/Const/recipes.php @@ -1,5 +1,5 @@ 'monday', 2 => 'tuesday', 3 => 'wednesday', 4 => 'thursday', 5 => 'friday', 6 => 'saturday', 0 => 'sunday' )); \ No newline at end of file