Compare commits

..

1 Commits

Author SHA1 Message Date
David Katrinka
947616f0ff TIST-17: added single recipe page 2025-06-28 15:32:35 +02:00
11 changed files with 54 additions and 188 deletions

View File

@ -22,7 +22,6 @@ The FridgeBites was developed almost entirely from scratch using PHP, without re
The website is built entirely from scratch using pure PHP, without relying on any frameworks. This was done as an experimental project to enhance personal skills. Despite this, some libraries were used to add specific functionality: The website is built entirely from scratch using pure PHP, without relying on any frameworks. This was done as an experimental project to enhance personal skills. Despite this, some libraries were used to add specific functionality:
- [\[PHP\] PHPMailer](https://github.com/PHPMailer/PHPMailer): A library for sending emails, used for password recovery functionality. - [\[PHP\] PHPMailer](https://github.com/PHPMailer/PHPMailer): A library for sending emails, used for password recovery functionality.
- [\[PHP\] FPHP](https://www.fpdf.org/): library which allows to generate PDF files with pure PHP, that is to say without using the PDFlib library.
- [\[JS\] Swiper.js](https://github.com/nolimits4web/swiper): A highly customizable library for creating sliders and carousels. - [\[JS\] Swiper.js](https://github.com/nolimits4web/swiper): A highly customizable library for creating sliders and carousels.
- [\[JS\] Toastify.js](https://github.com/apvarun/toastify-js): A lightweight library for creating beautiful and customizable toast notifications. - [\[JS\] Toastify.js](https://github.com/apvarun/toastify-js): A lightweight library for creating beautiful and customizable toast notifications.

View File

@ -3,7 +3,6 @@
namespace Lycoreco\Apps\Ajax\Controllers; namespace Lycoreco\Apps\Ajax\Controllers;
use Lycoreco\Includes\BaseController; use Lycoreco\Includes\BaseController;
use Lycoreco\Includes\Model\ValidationError;
class AjaxController extends BaseController class AjaxController extends BaseController
{ {
@ -33,15 +32,8 @@ class AjaxController extends BaseController
try { try {
$context['result'] = $action(); $context['result'] = $action();
} } catch (\Exception $ex) {
catch (ValidationError $ex) {
$context['result'] = get_ajax_error($ex->getMessage(), 400);
return $context;
}
catch (\Exception $ex) {
http_response_code(500);
$context['result'] = get_ajax_error($ex->getMessage()); $context['result'] = get_ajax_error($ex->getMessage());
return $context;
} }

View File

@ -1,2 +1,2 @@
<?php <?php
echo json_encode($context['result'], JSON_PRETTY_PRINT); echo $context['result'];

View File

@ -1,9 +1,6 @@
<?php <?php
use Lycoreco\Apps\Recipes\Models\{ use Lycoreco\Apps\Recipes\Models\RecipeModel;
RecipeModel,
RecipeUserMenu
};
function get_ajax_error($message, $error_code = 500) function get_ajax_error($message, $error_code = 500)
{ {
@ -12,14 +9,13 @@ function get_ajax_error($message, $error_code = 500)
$error = array(); $error = array();
$error['error'] = $message; $error['error'] = $message;
return $error; return json_encode($error, JSON_PRETTY_PRINT);
} }
/** /**
* Ajax actions * Ajax actions
*/ */
function ajax_search() function ajax_search() {
{
$search_query = $_POST['query'] ?? null; $search_query = $_POST['query'] ?? null;
if (!isset($search_query)) { if (!isset($search_query)) {
return get_ajax_error("Missing 'query' parameter.", 400); return get_ajax_error("Missing 'query' parameter.", 400);
@ -41,59 +37,5 @@ function ajax_search()
$result['count'] = count($recipes); $result['count'] = count($recipes);
$result['result'] = $recipes; $result['result'] = $recipes;
return $result; return json_encode($result, JSON_PRETTY_PRINT);
}
function ajax_usermenu()
{
$recipe_id = $_POST['recipe_id'] ?? null;
$dayofweek = $_POST['dayofweek'] ?? null;
if (!CURRENT_USER) {
return get_ajax_error('You are not authorized', 401);
}
if (!isset($recipe_id)) {
return get_ajax_error("Missing 'recipe_id' parameter.", 400);
}
if (!isset($dayofweek)) {
return get_ajax_error("Missing 'dayofweek' parameter.", 400);
}
$result = array();
$user_menu = RecipeUserMenu::get(array(
[
'name' => 'obj.recipe_id',
'type' => '=',
'value' => $recipe_id
],
[
'name' => 'obj.user_id',
'type' => '=',
'value' => CURRENT_USER->get_id()
]
));
// If user choose optiopn 'remove'
if($dayofweek == 'remove') {
if($user_menu) {
$user_menu->delete();
$result['success'] = 'This recipe was removed from your list';
return $result;
}
else {
return get_ajax_error("This recipe in your menu is not exists", 400);
}
}
// If not exists, add new recipe in user menu
if(!$user_menu) {
$user_menu = new RecipeUserMenu();
$user_menu->field_recipe_id = $recipe_id;
$user_menu->field_user_id = CURRENT_USER->get_id();
}
$user_menu->field_dayofweek = $dayofweek;
$user_menu->save();
$result['success'] = 'You have successfully added the recipe to your menu.';
return $result;
} }

View File

@ -17,7 +17,7 @@ class RecipeModel extends BaseModel
public $category_name; public $category_name;
const STATUS = [['publish', 'Publish'], ['pending', 'Pending']]; const STATUS = [[ 'publish', 'Publish' ], [ 'pending', 'Pending' ]];
static protected $search_fields = ['obj.title']; static protected $search_fields = ['obj.title'];
static protected $table_name = 'recipes'; static protected $table_name = 'recipes';
@ -76,20 +76,10 @@ class RecipeModel extends BaseModel
{ {
return ucfirst($this->field_status); return ucfirst($this->field_status);
} }
public function get_image_url() public function get_image_url() {
{ if($this->field_image_url)
if ($this->field_image_url)
return MEDIA_URL . $this->field_image_url; return MEDIA_URL . $this->field_image_url;
return null; return null;
} }
public function get_html_instruction(): string
{
return nl2br(trim($this->field_instruction));
}
public function get_time(){
return $this->field_estimated_time . " minutes";
}
} }

View File

@ -1,57 +0,0 @@
<?php
namespace Lycoreco\Apps\Recipes\Models;
use Lycoreco\Includes\Model\BaseModel;
class RecipeUserMenu extends BaseModel
{
public $field_dayofweek;
public $field_recipe_id;
public $field_user_id;
public $field_created_at;
static protected $table_name = 'recipe_usermenu';
static protected $table_fields = [
'id' => 'int',
'dayofweek' => 'string',
'recipe_id' => 'int',
'user_id' => 'int',
'created_at' => 'DateTime'
];
public static function init_table()
{
$result = db_query('CREATE TABLE ' . static::$table_name . ' (
id INT AUTO_INCREMENT PRIMARY KEY,
dayofweek VARCHAR(150) NOT NULL,
recipe_id INT NOT NULL,
user_id INT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);');
return $result;
}
public function valid()
{
require_once INCLUDES_PATH . '/Const/recipes.php';
if(!in_array($this->field_dayofweek, DAYS_OF_WEEK))
return ['Day of Week is not valid'];
$recipe = RecipeModel::get(array(
[
'name' => 'obj.id',
'type' => '=',
'value' => $this->field_recipe_id
]
));
if(!$recipe)
return ['Recipe is not exists'];
return true;
}
}

View File

@ -1,5 +1,4 @@
<?php <?php
require_once(INCLUDES_PATH . '/Const/recipes.php');
the_header( the_header(
$context['recipe']->field_title, $context['recipe']->field_title,
'This is a single recipe page where you can view the details of the recipe, including ingredients, instructions, and more.', 'This is a single recipe page where you can view the details of the recipe, including ingredients, instructions, and more.',
@ -37,7 +36,7 @@ the_header(
</div> </div>
<div class="single-recipe-data__item"> <div class="single-recipe-data__item">
<span class="data-name">Time To Make: </span> <span class="data-name">Time To Make: </span>
<span class="data"><?php echo $context['recipe']->get_time(); ?></span> <span class="data"><?php echo $context['recipe']->field_estimated_time; ?> minutes</span>
</div> </div>
<div class="single-recipe-data__item"> <div class="single-recipe-data__item">
<span class="data-name">Ingredients: </span> <span class="data-name">Ingredients: </span>
@ -50,9 +49,13 @@ the_header(
</div> </div>
<div class="button-ctrl"> <div class="button-ctrl">
<select class="hidden" name="daily-meal-select" id="daily-meal-day"> <select class="hidden" name="daily-meal-select" id="daily-meal-day">
<?php foreach (DAYS_OF_WEEK as $day): ?> <option value="monday">Monday</option>
<option value="<?= $day ?>"><?= ucfirst($day) ?></option> <option value="tuesday">Tuesday</option>
<?php endforeach; ?> <option value="wednesday">Wednesday</option>
<option value="thursday">Thursday</option>
<option value="friday">Friday</option>
<option value="saturday">Saturday</option>
<option value="sunday">Sunday</option>
<option value="remove">Remove From List</option> <option value="remove">Remove From List</option>
</select> </select>
<div class="day-select-wrapper"> <div class="day-select-wrapper">
@ -62,13 +65,14 @@ the_header(
<i class="fa-solid fa-list select-icon"></i> <i class="fa-solid fa-list select-icon"></i>
</div> </div>
<div id="custom-select-dropdown" class="custom-select-dropdown hidden"> <div id="custom-select-dropdown" class="custom-select-dropdown hidden">
<?php foreach (DAYS_OF_WEEK as $day): ?> <div class="dropdown-item hover-anim" data-value="monday">Monday</div>
<div class="dropdown-item hover-anim" data-value="<?= $day?>"> <div class="dropdown-item hover-anim" data-value="tuesday">Tuesday</div>
<?= ucfirst($day) ?> <div class="dropdown-item hover-anim" data-value="wednesday">Wednesday</div>
</div> <div class="dropdown-item hover-anim" data-value="thursday">Thursday</div>
<?php endforeach; ?> <div class="dropdown-item hover-anim" data-value="friday">Friday</div>
<div class="dropdown-item hover-anim" data-value="saturday">Saturday</div>
<div class="dropdown-item hover-anim" data-value="sunday">Sunday</div>
<div class="dropdown-item hover-anim" data-value="remove">Remove From List</div> <div class="dropdown-item hover-anim" data-value="remove">Remove From List</div>
</div> </div>
</div> </div>
<div class="small-btns"> <div class="small-btns">
@ -98,7 +102,11 @@ the_header(
<div class="single-instructions"> <div class="single-instructions">
<h2 class="title">Instructions</h2> <h2 class="title">Instructions</h2>
<?= $context['recipe']->get_html_instruction(); ?> <?php
$formatted = preg_replace('/(\d+\.\s)/', "\n$1", $context['recipe']->field_instruction);
echo nl2br(trim($formatted));
?>
</div> </div>
<div class="single-ingredients"> <div class="single-ingredients">
<h2 class="title">Ingredients</h2> <h2 class="title">Ingredients</h2>
@ -126,8 +134,6 @@ the_header(
</div> </div>
<?php the_footer(array( <?php the_footer(array(
ASSETS_PATH . '/js/single.js', ASSETS_PATH . '/js/single.js',
)); ?> )); ?>

File diff suppressed because one or more lines are too long

View File

@ -20,7 +20,7 @@
<script src="<?php echo ASSETS_PATH . '/js/main.js' ?>"></script> <script src="<?php echo ASSETS_PATH . '/js/main.js' ?>"></script>
<script src="<?php echo ASSETS_PATH . '/toastify/toastify-js.js' ?>"></script> <script src="<?php echo ASSETS_PATH . '/toastify/toastify-js.js' ?>"></script>
<script src="<?php echo ASSETS_PATH . '/qrcode/qrcode.min.js' ?>"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
<?php foreach($scripts as $script): ?> <?php foreach($scripts as $script): ?>
<script src="<?php echo $script ?>"></script> <script src="<?php echo $script ?>"></script>
<?php endforeach; ?> <?php endforeach; ?>

View File

@ -1,5 +0,0 @@
<?php
define('DAYS_OF_WEEK', array(
'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday'
));

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 KiB