Compare commits
4 Commits
9f2d2a13d2
...
36e7435bd4
| Author | SHA1 | Date | |
|---|---|---|---|
| 36e7435bd4 | |||
| 26cf158ec5 | |||
| e2fe1a4173 | |||
| 9fc579fc56 |
@ -50,6 +50,12 @@ class AdminDeleteController extends Abstract\AdminBaseController
|
|||||||
'field_display' => 'ingredient_name',
|
'field_display' => 'ingredient_name',
|
||||||
'back_to' => 'admin:ing-cat-rel',
|
'back_to' => 'admin:ing-cat-rel',
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'url_name' => 'recipe-reviews',
|
||||||
|
'model' => 'Lycoreco\Apps\Recipes\Models\ReviewsModel',
|
||||||
|
'field_display' => 'field_title',
|
||||||
|
'back_to' => 'admin:review',
|
||||||
|
],
|
||||||
];
|
];
|
||||||
|
|
||||||
protected $template_name = APPS_PATH . '/Admin/Templates/delete.php';
|
protected $template_name = APPS_PATH . '/Admin/Templates/delete.php';
|
||||||
|
|||||||
44
apps/Admin/Controllers/AdminReviewControler.php
Normal file
44
apps/Admin/Controllers/AdminReviewControler.php
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lycoreco\Apps\Admin\Controllers;
|
||||||
|
|
||||||
|
use Lycoreco\Apps\Recipes\Models\ReviewsModel;
|
||||||
|
|
||||||
|
class AdminReviewControler extends Abstract\AdminSingleController
|
||||||
|
{
|
||||||
|
protected $model_сlass_name = "Lycoreco\Apps\Recipes\Models\ReviewsModel";
|
||||||
|
protected $field_title = 'field_title';
|
||||||
|
protected $verbose_name = 'review';
|
||||||
|
protected $object_router_name = 'admin:review';
|
||||||
|
|
||||||
|
protected $fields = array(
|
||||||
|
[
|
||||||
|
'model_field' => 'title',
|
||||||
|
'input_type' => 'text',
|
||||||
|
'input_attrs' => ['required']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'model_field' => 'rating',
|
||||||
|
'input_type' => 'number',
|
||||||
|
'input_attrs' => ['required']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'model_field' => 'content',
|
||||||
|
'input_type' => 'textarea',
|
||||||
|
'input_attrs' => ['required']
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'model_field' => 'status',
|
||||||
|
'input_type' => 'select',
|
||||||
|
'input_attrs' => ['required'],
|
||||||
|
'input_values' => ReviewsModel::STATUS
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'model_field' => 'created_at',
|
||||||
|
'input_type' => 'text',
|
||||||
|
'dynamic_save' => false,
|
||||||
|
'input_label' => 'Created at',
|
||||||
|
'input_attrs' => ['disabled']
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}
|
||||||
17
apps/Admin/Controllers/AdminReviewListController.php
Normal file
17
apps/Admin/Controllers/AdminReviewListController.php
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lycoreco\Apps\Admin\Controllers;
|
||||||
|
|
||||||
|
class AdminReviewListController extends Abstract\AdminListController
|
||||||
|
{
|
||||||
|
protected $model_сlass_name = "Lycoreco\Apps\Recipes\Models\ReviewsModel";
|
||||||
|
protected $table_fields = array(
|
||||||
|
'Title' => 'field_title',
|
||||||
|
'Rating' => 'field_rating',
|
||||||
|
'Status ' => 'get_status()',
|
||||||
|
'Creaated at' => 'field_created_at',
|
||||||
|
);
|
||||||
|
protected $single_router_name = 'admin:review';
|
||||||
|
protected $verbose_name = "review";
|
||||||
|
protected $verbose_name_multiply = "reviews";
|
||||||
|
}
|
||||||
@ -26,6 +26,11 @@ $sidebar_links = [
|
|||||||
'name' => 'Ingredients',
|
'name' => 'Ingredients',
|
||||||
'icon' => 'fa-solid fa-carrot',
|
'icon' => 'fa-solid fa-carrot',
|
||||||
'router_name' => 'admin:ingredient-list'
|
'router_name' => 'admin:ingredient-list'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'Reviews',
|
||||||
|
'icon' => 'fa-solid fa-comment',
|
||||||
|
'router_name' => 'admin:review-list'
|
||||||
]
|
]
|
||||||
];
|
];
|
||||||
?>
|
?>
|
||||||
|
|||||||
@ -12,6 +12,7 @@ $admin_urls = [
|
|||||||
new Path('/admin/recipes',new Controllers\AdminRecipeListController(), 'recipe-list'),
|
new Path('/admin/recipes',new Controllers\AdminRecipeListController(), 'recipe-list'),
|
||||||
new Path('/admin/categories',new Controllers\AdminCategoryListController(), 'category-list'),
|
new Path('/admin/categories',new Controllers\AdminCategoryListController(), 'category-list'),
|
||||||
new Path('/admin/ingredients',new Controllers\IngredientListController(), 'ingredient-list'),
|
new Path('/admin/ingredients',new Controllers\IngredientListController(), 'ingredient-list'),
|
||||||
|
new Path('/admin/reviews', new Controllers\AdminReviewListController(), 'review-list'),
|
||||||
|
|
||||||
////// Single object ///////
|
////// Single object ///////
|
||||||
// User
|
// User
|
||||||
@ -35,6 +36,9 @@ $admin_urls = [
|
|||||||
new Path('/admin/ingredient/[:int]', new Controllers\IngredientController(), 'ingredient'),
|
new Path('/admin/ingredient/[:int]', new Controllers\IngredientController(), 'ingredient'),
|
||||||
new Path('/admin/ingredient/new', new Controllers\IngredientController(true), 'ingredient-new'),
|
new Path('/admin/ingredient/new', new Controllers\IngredientController(true), 'ingredient-new'),
|
||||||
|
|
||||||
|
// Reviews
|
||||||
|
new Path('/admin/review/[:int]', new Controllers\AdminReviewControler(), 'review'),
|
||||||
|
|
||||||
// Recipe ingedient relation
|
// Recipe ingedient relation
|
||||||
new Path('/admin/recipe/[:int]/ingredients', new Controllers\IngredientRecipeRelListController(), 'ing-cat-rel-list'),
|
new Path('/admin/recipe/[:int]/ingredients', new Controllers\IngredientRecipeRelListController(), 'ing-cat-rel-list'),
|
||||||
new Path('/admin/recipe/ingredient/[:int]', new Controllers\IngredientRecipeRelController(), 'ing-cat-rel'),
|
new Path('/admin/recipe/ingredient/[:int]', new Controllers\IngredientRecipeRelController(), 'ing-cat-rel'),
|
||||||
|
|||||||
@ -5,6 +5,7 @@ namespace Lycoreco\Apps\Index\Controllers;
|
|||||||
use Lycoreco\Apps\Recipes\Models\CategoryModel;
|
use Lycoreco\Apps\Recipes\Models\CategoryModel;
|
||||||
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
||||||
use Lycoreco\Apps\Recipes\Models\RecipeUserMenu;
|
use Lycoreco\Apps\Recipes\Models\RecipeUserMenu;
|
||||||
|
use Lycoreco\Apps\Recipes\Models\ReviewsModel;
|
||||||
use Lycoreco\Includes\BaseController;
|
use Lycoreco\Includes\BaseController;
|
||||||
|
|
||||||
require_once(INCLUDES_PATH . '/Const/recipes.php');
|
require_once(INCLUDES_PATH . '/Const/recipes.php');
|
||||||
@ -29,6 +30,16 @@ class HomepageController extends BaseController
|
|||||||
$dayNumber = date("w");
|
$dayNumber = date("w");
|
||||||
$dayofweek = DAYS_OF_WEEK[$dayNumber];
|
$dayofweek = DAYS_OF_WEEK[$dayNumber];
|
||||||
|
|
||||||
|
$context['reviews'] = ReviewsModel::filter(array(
|
||||||
|
[
|
||||||
|
'name' => 'obj.status',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => 'publish'
|
||||||
|
]),
|
||||||
|
['-obj.created_at'],
|
||||||
|
6
|
||||||
|
);
|
||||||
|
|
||||||
if(CURRENT_USER) {
|
if(CURRENT_USER) {
|
||||||
$context['usermenu_recipe_prefetch'] = RecipeUserMenu::get_prefetch_recipes(CURRENT_USER, $dayofweek);
|
$context['usermenu_recipe_prefetch'] = RecipeUserMenu::get_prefetch_recipes(CURRENT_USER, $dayofweek);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -86,104 +86,23 @@ the_header(
|
|||||||
<div class="recent-reviews">
|
<div class="recent-reviews">
|
||||||
<h2 class="title">Recent User Reviews</h2>
|
<h2 class="title">Recent User Reviews</h2>
|
||||||
<div class="reviews-grid">
|
<div class="reviews-grid">
|
||||||
<a href="#" class="recent-review hover-anim">
|
<?php foreach($context['reviews'] as $review): ?>
|
||||||
|
<a href="<?php the_permalink('recipes:single', [$review->field_recipe_id]) ?>" class="recent-review hover-anim">
|
||||||
<div class="review-title">
|
<div class="review-title">
|
||||||
<div class="review-img">
|
<div class="review-img">
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
<img src="<?= $review->get_recipe_image() ?>" alt="reviewed recipe">
|
||||||
</div>
|
</div>
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
<h3 class="review-title-text"><?= $review->recipe_title ?></h3>
|
||||||
</div>
|
</div>
|
||||||
<div class="review-text">
|
<div class="review-text">
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
<p><?= $review->get_excerpt() ?></p>
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="review-meta meta">
|
<div class="review-meta meta">
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
<p class="review-author"><i class="fa-solid fa-user"></i> <?= $review->author_username ?></p>
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> <?= $review->get_date() ?></p>
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<a href="#" class="recent-review hover-anim">
|
|
||||||
<div class="review-title">
|
|
||||||
<div class="review-img">
|
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
|
||||||
</div>
|
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
|
||||||
</div>
|
|
||||||
<div class="review-text">
|
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
|
||||||
<div class="review-meta meta">
|
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
|
||||||
</div>
|
|
||||||
</a><a href="#" class="recent-review hover-anim">
|
|
||||||
<div class="review-title">
|
|
||||||
<div class="review-img">
|
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
|
||||||
</div>
|
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
|
||||||
</div>
|
|
||||||
<div class="review-text">
|
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
|
||||||
<div class="review-meta meta">
|
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
|
||||||
</div>
|
|
||||||
</a><a href="#" class="recent-review hover-anim">
|
|
||||||
<div class="review-title">
|
|
||||||
<div class="review-img">
|
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
|
||||||
</div>
|
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
|
||||||
</div>
|
|
||||||
<div class="review-text">
|
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
|
||||||
<div class="review-meta meta">
|
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
|
||||||
</div>
|
|
||||||
</a><a href="#" class="recent-review hover-anim">
|
|
||||||
<div class="review-title">
|
|
||||||
<div class="review-img">
|
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
|
||||||
</div>
|
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
|
||||||
</div>
|
|
||||||
<div class="review-text">
|
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
|
||||||
<div class="review-meta meta">
|
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
|
||||||
</div>
|
|
||||||
</a><a href="#" class="recent-review hover-anim">
|
|
||||||
<div class="review-title">
|
|
||||||
<div class="review-img">
|
|
||||||
<img src="media/recipe1.jpeg" alt="reviewed recipe">
|
|
||||||
</div>
|
|
||||||
<h3 class="review-title-text">Just Like Mom's</h3>
|
|
||||||
</div>
|
|
||||||
<div class="review-text">
|
|
||||||
<p>I made this spaghetti last night and it was absolutely delicious! The sauce was rich and
|
|
||||||
flavorful—just the right balance of garlic, herbs, and tomato. I added a pinch of chili
|
|
||||||
flakes for a little kick, and it turned out perfect...</p>
|
|
||||||
</div>
|
|
||||||
<div class="review-meta meta">
|
|
||||||
<p class="review-author"><i class="fa-solid fa-user"></i> GreenDavid004</p>
|
|
||||||
<p class="review-date"><i class="fa-solid fa-calendar-days"></i> 2023-10-01</p>
|
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php if(CURRENT_USER): ?>
|
<?php if(CURRENT_USER): ?>
|
||||||
|
|||||||
@ -2,16 +2,51 @@
|
|||||||
|
|
||||||
namespace Lycoreco\Apps\Recipes\Controllers;
|
namespace Lycoreco\Apps\Recipes\Controllers;
|
||||||
|
|
||||||
|
use Exception;
|
||||||
use Lycoreco\Apps\Recipes\Models\IngredientInRecipeModel;
|
use Lycoreco\Apps\Recipes\Models\IngredientInRecipeModel;
|
||||||
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
use Lycoreco\Apps\Recipes\Models\RecipeModel;
|
||||||
|
use Lycoreco\Apps\Recipes\Models\ReviewsModel;
|
||||||
use Lycoreco\Apps\Users\Models\UserModel;
|
use Lycoreco\Apps\Users\Models\UserModel;
|
||||||
use Lycoreco\Includes\BaseController;
|
use Lycoreco\Includes\BaseController;
|
||||||
|
use Lycoreco\Includes\Model\ValidationError;
|
||||||
use Lycoreco\Includes\Routing\HttpExceptions;
|
use Lycoreco\Includes\Routing\HttpExceptions;
|
||||||
|
|
||||||
class SingleRecipeController extends BaseController
|
class SingleRecipeController extends BaseController
|
||||||
{
|
{
|
||||||
protected $template_name = APPS_PATH . '/Recipes/Templates/single.php';
|
protected $template_name = APPS_PATH . '/Recipes/Templates/single.php';
|
||||||
|
|
||||||
|
protected function post()
|
||||||
|
{
|
||||||
|
if(!CURRENT_USER) {
|
||||||
|
$this->context['reviews_error'] = 'You are not authorized';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$rating = $_POST['rating-select'] ?? null;
|
||||||
|
$title = $_POST['review-title'] ?? null;
|
||||||
|
$content = $_POST['review-body-input'] ?? null;
|
||||||
|
|
||||||
|
$recipe = $this->get_model();
|
||||||
|
|
||||||
|
$review = new ReviewsModel();
|
||||||
|
$review->field_title = $title;
|
||||||
|
$review->field_content = $content;
|
||||||
|
$review->field_rating = $rating;
|
||||||
|
$review->field_status = 'pending';
|
||||||
|
$review->field_user_id = CURRENT_USER->get_id();
|
||||||
|
$review->field_recipe_id = $recipe->get_id();
|
||||||
|
|
||||||
|
try {
|
||||||
|
$review->save();
|
||||||
|
$this->context['display_review_form'] = false;
|
||||||
|
}
|
||||||
|
catch(ValidationError $ex) {
|
||||||
|
$this->context['reviews_error'] = $ex->getMessage();
|
||||||
|
}
|
||||||
|
catch(Exception $ex) {
|
||||||
|
$this->context['reviews_error'] = 'Unexpected error';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function get_model()
|
protected function get_model()
|
||||||
{
|
{
|
||||||
if (isset($this->__model))
|
if (isset($this->__model))
|
||||||
@ -39,6 +74,7 @@ class SingleRecipeController extends BaseController
|
|||||||
|
|
||||||
|
|
||||||
$context['recipe'] = $recipe;
|
$context['recipe'] = $recipe;
|
||||||
|
$context['display_review_form'] = true;
|
||||||
|
|
||||||
$context['author'] = UserModel::get(array(
|
$context['author'] = UserModel::get(array(
|
||||||
[
|
[
|
||||||
@ -56,6 +92,42 @@ class SingleRecipeController extends BaseController
|
|||||||
]
|
]
|
||||||
));
|
));
|
||||||
|
|
||||||
|
$context['reviews'] = ReviewsModel::filter(array(
|
||||||
|
[
|
||||||
|
'name' => 'obj.recipe_id',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => $recipe->get_id()
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'obj.status',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => 'publish'
|
||||||
|
],
|
||||||
|
));
|
||||||
|
$context['reviews_average'] = '0.0';
|
||||||
|
if(!empty($context['reviews'])) {
|
||||||
|
$sum = array_sum(array_column($context['reviews'], 'field_rating'));
|
||||||
|
$count = count($context['reviews']);
|
||||||
|
$context['reviews_average'] = number_format($sum / $count, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CURRENT_USER) {
|
||||||
|
$review_exists = ReviewsModel::count(array(
|
||||||
|
[
|
||||||
|
'name' => 'obj.recipe_id',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => $recipe->get_id()
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'name' => 'obj.user_id',
|
||||||
|
'type' => '=',
|
||||||
|
'value' => CURRENT_USER->get_id()
|
||||||
|
]
|
||||||
|
));
|
||||||
|
if($review_exists > 0)
|
||||||
|
$context['display_review_form'] = false;
|
||||||
|
}
|
||||||
|
|
||||||
return $context;
|
return $context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
apps/Recipes/Controllers/SingleSubmitController.php
Normal file
21
apps/Recipes/Controllers/SingleSubmitController.php
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lycoreco\Apps\Recipes\Controllers;
|
||||||
|
|
||||||
|
use Lycoreco\Includes\BaseController;
|
||||||
|
use Lycoreco\Apps\Recipes\Models\CategoryModel;
|
||||||
|
|
||||||
|
class SingleSubmitController extends BaseController
|
||||||
|
{
|
||||||
|
protected $template_name = APPS_PATH . '/Recipes/Templates/single-submit.php';
|
||||||
|
|
||||||
|
public function get_context_data()
|
||||||
|
{
|
||||||
|
$context = parent::get_context_data();
|
||||||
|
|
||||||
|
$context['category_options'] = CategoryModel::get_cat_values();
|
||||||
|
|
||||||
|
|
||||||
|
return $context;
|
||||||
|
}
|
||||||
|
}
|
||||||
121
apps/Recipes/Models/ReviewsModel.php
Normal file
121
apps/Recipes/Models/ReviewsModel.php
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Lycoreco\Apps\Recipes\Models;
|
||||||
|
|
||||||
|
use DateTime;
|
||||||
|
use Lycoreco\Includes\Model\BaseModel;
|
||||||
|
|
||||||
|
class ReviewsModel extends BaseModel
|
||||||
|
{
|
||||||
|
const STATUS = [['publish', 'Publish'], ['pending', 'Pending']];
|
||||||
|
|
||||||
|
public $field_title;
|
||||||
|
public $field_content;
|
||||||
|
public $field_rating;
|
||||||
|
public $field_status;
|
||||||
|
public $field_recipe_id;
|
||||||
|
public $field_user_id;
|
||||||
|
public $field_created_at;
|
||||||
|
|
||||||
|
public $author_username;
|
||||||
|
public $recipe_title;
|
||||||
|
public $recipe_image;
|
||||||
|
|
||||||
|
static protected $search_fields = ['obj.title'];
|
||||||
|
static protected $table_name = 'recipe_reviews';
|
||||||
|
static protected $table_fields = [
|
||||||
|
'id' => 'int',
|
||||||
|
'title' => 'string',
|
||||||
|
'content' => 'string',
|
||||||
|
'rating' => 'int',
|
||||||
|
'status' => 'string',
|
||||||
|
|
||||||
|
'recipe_id' => 'int',
|
||||||
|
'user_id' => 'int',
|
||||||
|
'created_at' => 'DateTime',
|
||||||
|
];
|
||||||
|
static protected $additional_fields = array(
|
||||||
|
[
|
||||||
|
'field' => [
|
||||||
|
'us.username AS author_username'
|
||||||
|
],
|
||||||
|
'join_table' => 'users us ON us.id = obj.user_id'
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'field' => [
|
||||||
|
're.title AS recipe_title',
|
||||||
|
're.image_url AS recipe_image'
|
||||||
|
],
|
||||||
|
'join_table' => 'recipes re ON re.id = obj.recipe_id'
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
public static function init_table()
|
||||||
|
{
|
||||||
|
$result = db_query('CREATE TABLE ' . static::$table_name . ' (
|
||||||
|
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
|
||||||
|
title VARCHAR(255) NOT NULL,
|
||||||
|
content TEXT NOT NULL,
|
||||||
|
rating INT NOT NULL,
|
||||||
|
status VARCHAR(20) NOT NULL CHECK (status IN (\'publish\', \'pending\')),
|
||||||
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
recipe_id INT NOT NULL,
|
||||||
|
user_id INT NOT NULL,
|
||||||
|
|
||||||
|
FOREIGN KEY (recipe_id) REFERENCES recipes(id) ON DELETE CASCADE,
|
||||||
|
FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
|
||||||
|
);');
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_html_content(): string
|
||||||
|
{
|
||||||
|
return nl2br(trim($this->field_content));
|
||||||
|
}
|
||||||
|
public function get_status()
|
||||||
|
{
|
||||||
|
return ucfirst($this->field_status);
|
||||||
|
}
|
||||||
|
public function get_date()
|
||||||
|
{
|
||||||
|
$date = new DateTime($this->field_created_at);
|
||||||
|
return $date->format('d.m.Y');
|
||||||
|
}
|
||||||
|
public function get_excerpt()
|
||||||
|
{
|
||||||
|
$max_length = 100;
|
||||||
|
$excerpt = mb_substr($this->field_content, 0, $max_length);
|
||||||
|
|
||||||
|
if(mb_strlen($this->field_content) > $max_length)
|
||||||
|
$excerpt .= '...';
|
||||||
|
|
||||||
|
return $excerpt;
|
||||||
|
}
|
||||||
|
public function get_recipe_image()
|
||||||
|
{
|
||||||
|
$recipe = new RecipeModel();
|
||||||
|
$recipe->field_image_url = $this->recipe_image;
|
||||||
|
return $recipe->get_image_url();
|
||||||
|
}
|
||||||
|
public function valid() {
|
||||||
|
$errors = array();
|
||||||
|
|
||||||
|
if(empty($this->field_title))
|
||||||
|
$errors[] = 'Title field is empty';
|
||||||
|
|
||||||
|
if(empty($this->field_content))
|
||||||
|
$errors[] = 'Content field is empty';
|
||||||
|
|
||||||
|
$this->field_rating = (int)$this->field_rating;
|
||||||
|
if($this->field_rating < 1 || $this->field_rating > 5) {
|
||||||
|
$errors[] = 'Rating must be between 1 and 5';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (empty($errors))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return $errors;
|
||||||
|
}
|
||||||
|
}
|
||||||
90
apps/Recipes/Templates/single-submit.php
Normal file
90
apps/Recipes/Templates/single-submit.php
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?php
|
||||||
|
the_header(
|
||||||
|
'Submit a Recipe',
|
||||||
|
'Share your culinary creations with the world! Fill out the form below to submit your recipe for review and publication.',
|
||||||
|
'submit-recipe-body',
|
||||||
|
[
|
||||||
|
|
||||||
|
['keywords', 'recipe, submit, share, cooking, culinary'],
|
||||||
|
]
|
||||||
|
);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<div class="submit-recipe">
|
||||||
|
<h1 class="title">Submit a Recipe</h1>
|
||||||
|
</div>
|
||||||
|
<form action="" class="single-submit-form" method="post" enctype="multipart/form-data">
|
||||||
|
<label for="title-input">Title</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" id="title-input" name="title" placeholder="Enter the recipe title" required>
|
||||||
|
</div>
|
||||||
|
<label for="description-input">Description</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<textarea id="description-input" name="description" placeholder="Describe your recipe in detail"
|
||||||
|
required></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="ingredients-input">Ingredients</label><span>*</span>
|
||||||
|
<button type="button" id="add-ingredient-btn" class="btn btn-primary hover-anim add-ingredient-btn">Add new
|
||||||
|
ingredient</button>
|
||||||
|
<div id="overlay" class="hidden"></div>
|
||||||
|
<div class="ing-modal hidden" id="ingredient-modal">
|
||||||
|
<div id="new-ingredient">
|
||||||
|
<label for="ing-name-input">Ingredient Name</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" id="ing-name-input" name="title" placeholder="Enter the ingredient name"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<label for="unit-input">Unit of measure</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" id="ing-unit-input" name="title" placeholder="Enter the unit of measure"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<button type="button" id="new-ingredient-submit" class="btn btn-primary hover-anim">Add new ingredient</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="input">
|
||||||
|
select 2 goes here
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="image-input">Image</label><span>*</span>
|
||||||
|
<div class="input-file">
|
||||||
|
<input type="file" id="image-input" name="image" accept="image/*" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="time-input">Estimated Time (minutes)</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" id="time-input" name="est-time" placeholder="Enter the recipe estimated time" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<label for="price-input">Estimated Price ($)</label><span>*</span>
|
||||||
|
<div class="input">
|
||||||
|
<input type="text" id="price-input" name="est-price" placeholder="Enter the recipe estimated price"
|
||||||
|
required>
|
||||||
|
</div>
|
||||||
|
<label for="category-select">Category</label><span>*</span>
|
||||||
|
<div class="input-select">
|
||||||
|
|
||||||
|
<select id="category-select" name="category" required>
|
||||||
|
<option value="">Select a category</option>
|
||||||
|
<?php foreach ($context['category_options'] as $category): ?>
|
||||||
|
<option value="<?php echo $category[0]; ?>">
|
||||||
|
<?php echo $category[1]; ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
</select>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="btn btn-primary hover-anim">Submit Recipe</button>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
<?php the_footer(array(
|
||||||
|
ASSETS_PATH . '/js/single-submit.js',
|
||||||
|
)); ?>
|
||||||
@ -130,45 +130,40 @@ the_header(
|
|||||||
</div>
|
</div>
|
||||||
<div class="single-recipe-reviews">
|
<div class="single-recipe-reviews">
|
||||||
<h2 class="title">Reviews</h2>
|
<h2 class="title">Reviews</h2>
|
||||||
<h3 class="rating">Average Rating: 4.5 <i class="fa-regular fa-star"></i></h3>
|
<h3 class="rating">Average Rating: <?= $context['reviews_average'] ?> <i class="fa-regular fa-star"></i></h3>
|
||||||
<div class="reviews">
|
<div class="reviews">
|
||||||
<div class="review-list">
|
<div class="review-list">
|
||||||
<h4 class="subtitle">All Reviews</h4>
|
<h4 class="subtitle">All Reviews</h4>
|
||||||
|
<?php if(empty($context['reviews'])): ?>
|
||||||
|
<div class="nothing">Nothing to show</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php foreach ($context['reviews'] as $review): ?>
|
||||||
<div class="review">
|
<div class="review">
|
||||||
<span class="review-title"> <i class="fa-solid fa-star"></i> 5 Divine disc of
|
<span class="review-title"><?= $review->field_rating ?> <i class="fa-solid fa-star"></i> <?= $review->field_title ?></span>
|
||||||
deliciousness!</span>
|
|
||||||
<div class="review-body">
|
<div class="review-body">
|
||||||
Blessings of Aqua-sama upon you, fellow foodies! As a proud and very sane member of the Axis
|
<?= $review->get_html_content() ?>
|
||||||
Cult, I recently partook in a holy culinary experience that rivaled even the sacred waters
|
|
||||||
of the Blue Lake: a homemade pepperoni and mushroom pizza!
|
|
||||||
The moment I laid eyes on that glorious golden crust, I knew—Aqua-sama herself must have
|
|
||||||
guided my ovens temperature dial! The cheese was melted with such heavenly grace,
|
|
||||||
stretching with every bite like the ribbons of our goddesss divine garments. The pepperoni?
|
|
||||||
Spicy circles of salvation! And the mushrooms—earthy little blessings sent straight from the
|
|
||||||
soil Aqua purifies daily!
|
|
||||||
The crust had the perfect balance of crispy edge and fluffy soul. It crackled like the
|
|
||||||
laughter of a cultist pranking a stubborn Eris follower (teehee~). Each bite sang praises in
|
|
||||||
my mouth: “Axis! Axis! AXIS!!”
|
|
||||||
Would I recommend this pizza? Of course! Id even offer it as tribute at the next festival
|
|
||||||
in Aquas honor. Try it yourself and bask in the savory enlightenment. And remember: if it
|
|
||||||
tastes weird, just pour holy water on it. Or beer. Aqua would approve either way.
|
|
||||||
Rating: 5 out of 5 Axis Blessings!(Any lower would be heresy.)
|
|
||||||
</div>
|
</div>
|
||||||
<div class="single-review-meta">
|
<div class="single-review-meta">
|
||||||
<div class="review-meta__user meta">
|
<div class="review-meta__user meta">
|
||||||
<i class="fa-regular fa-user"></i> GreenDavid004
|
<i class="fa-regular fa-user"></i> <?= $review->author_username ?>
|
||||||
</div>
|
</div>
|
||||||
<div class="review-meta__date meta"><?= date("d.m.Y"); ?></div>
|
<div class="review-meta__date meta"><?= $review->get_date() ?></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<?php endforeach; ?>
|
||||||
</div>
|
</div>
|
||||||
|
<?php if($context['display_review_form']): ?>
|
||||||
<div class="review-form">
|
<div class="review-form">
|
||||||
<h4 class="subtitle">Your Review</h4>
|
<h4 class="subtitle">Your Review</h4>
|
||||||
|
<?php if(isset($context['reviews_error'])) {
|
||||||
|
the_alert($context['reviews_error'], 'warning');
|
||||||
|
} ?>
|
||||||
<form id="review-form" class="review-form__form" method="post" action="#">
|
<form id="review-form" class="review-form__form" method="post" action="#">
|
||||||
<div class="rating-selection">
|
<div class="rating-selection">
|
||||||
<label for="rating-select">Choose rating: </label>
|
<label for="rating-select">Choose rating: </label>
|
||||||
<select name="rating-select" id="rating select">
|
<select name="rating-select" id="rating select">
|
||||||
<option value="0">Rating</option>
|
<option>Rating</option>
|
||||||
<option value="1">1 Star</option>
|
<option value="1">1 Star</option>
|
||||||
<option value="2">2 Star </option>
|
<option value="2">2 Star </option>
|
||||||
<option value="3">3 Star</option>
|
<option value="3">3 Star</option>
|
||||||
@ -184,8 +179,8 @@ the_header(
|
|||||||
|
|
||||||
<button type="submit" class="btn btn-primary hover-anim">Submit</button>
|
<button type="submit" class="btn btn-primary hover-anim">Submit</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -9,4 +9,5 @@ $recipes_urls = [
|
|||||||
new Path('/catalog', new Controllers\CatalogController(), 'catalog'),
|
new Path('/catalog', new Controllers\CatalogController(), 'catalog'),
|
||||||
new Path('/daily-meals', new Controllers\DailyMealsController, 'daily-meals'),
|
new Path('/daily-meals', new Controllers\DailyMealsController, 'daily-meals'),
|
||||||
new Path('/favorites', new Controllers\FavoritesController(), 'favorites'),
|
new Path('/favorites', new Controllers\FavoritesController(), 'favorites'),
|
||||||
|
new Path('/submit', new Controllers\SingleSubmitController(), 'single-submit'),
|
||||||
];
|
];
|
||||||
|
|||||||
@ -1217,7 +1217,42 @@ label {
|
|||||||
font-family: var(--common-font);
|
font-family: var(--common-font);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.submit-recipe {
|
||||||
|
margin-top: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-recipe .title{
|
||||||
|
text-align: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-file{
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-ingredient-btn{
|
||||||
|
margin-bottom: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.single-submit-form span{
|
||||||
|
color: #015847;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ing-modal{
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
border-radius: 10px;
|
||||||
|
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
|
||||||
|
z-index: 9999;
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
@media (max-width: 768px) {
|
||||||
|
|
||||||
|
|||||||
55
assets/js/single-submit.js
Normal file
55
assets/js/single-submit.js
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
const addIngredientBtn = document.getElementById('add-ingredient-btn');
|
||||||
|
const overlay = document.getElementById('overlay');
|
||||||
|
const ingModal = document.getElementById('ingredient-modal');
|
||||||
|
|
||||||
|
addIngredientBtn.addEventListener('click', () => {
|
||||||
|
ingModal.classList.remove('hidden');
|
||||||
|
overlay.classList.remove('hidden');
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
document.addEventListener('click', (e) => {
|
||||||
|
if (!ingModal.contains(e.target) && !addIngredientBtn.contains(e.target)) {
|
||||||
|
ingModal.classList.add('hidden');
|
||||||
|
overlay.classList.add('hidden');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const ingredientSubmitBtn = document.getElementById('new-ingredient-submit');
|
||||||
|
const ingredientName = document.getElementById('ing-name-input');
|
||||||
|
const ingredientUnit = document.getElementById('ing-unit-input');
|
||||||
|
|
||||||
|
ingredientSubmitBtn.addEventListener('click', async (e) => {
|
||||||
|
|
||||||
|
const name = ingredientName.value.trim();
|
||||||
|
const unit = ingredientUnit.value.trim();
|
||||||
|
|
||||||
|
if (!name || !unit) {
|
||||||
|
showToastify('Please fill in all fields.', 'error');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('action', 'create_ingredient');
|
||||||
|
formData.append('name', name);
|
||||||
|
formData.append('unit', unit);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
showToastify(json.success, 'success');
|
||||||
|
ingredientName.value = '';
|
||||||
|
ingredientUnit.value = '';
|
||||||
|
ingModal.classList.add('hidden');
|
||||||
|
overlay.classList.add('hidden');
|
||||||
|
});
|
||||||
Loading…
x
Reference in New Issue
Block a user