all atb changes

This commit is contained in:
Joey Kimsey
2025-02-05 23:57:17 -05:00
parent 2ac64e5c49
commit ffb82b1192
328 changed files with 12384 additions and 2477 deletions

View File

@ -0,0 +1,140 @@
<?php
/**
* app/plugins/reviews/controllers/admin/reviews.php
*
* This is the reviews admin controller.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Controllers\Admin;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Houdini\Classes\Navigation;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Classes\AdminController;
use TheTempusProject\Models\Review;
use TheTempusProject\Models\ReviewCategory;
use TheTempusProject\Classes\Forms;
class Reviews extends AdminController {
protected static $reviews;
protected static $categories;
public function __construct() {
parent::__construct();
self::$title = 'Admin - Reviews';
self::$reviews = new Review;
self::$categories = new ReviewCategory;
$view = Navigation::activePageSelect( 'nav.admin', '/admin/reviews' );
Components::set( 'ADMINNAV', $view );
}
public function index( $data = null ) {
$reviews = Views::simpleView( 'reviews.admin.reviewList', self::$reviews->list() );
$categories = Views::simpleView( 'reviews.admin.categoryList', self::$categories->list() );
Components::set( 'reviews', $reviews );
Components::set( 'reviewCategories', $categories );
Views::view( 'reviews.admin.dashboard' );
}
public function categoryView( $id = null ) {
$category = self::$categories->findById( $id );
if ( ! $category ) {
Issues::add( 'error', 'Unknown Category.' );
return $this->index();
}
Views::view( 'reviews.admin.category', $category );
}
public function categoryCreate( ) {
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'reviews.admin.categoryCreate' );
}
if ( ! Forms::check( 'categoryCreate' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'reviews.admin.categoryCreate' );
}
$result = self::$categories->create(
Input::post( 'name' ),
Input::post( 'slug' ),
);
if ( $result ) {
Issues::add( 'success', 'Your review category has been created.' );
return $this->index();
}
Issues::add( 'error', [ 'There was an unknown error submitting your data.' => Check::userErrors() ] );
Views::view( 'reviews.admin.categoryCreate' );
}
public function categoryEdit( $id = null ) {
$category = self::$categories->findById( $id );
if ( ! $category ) {
Issues::add( 'error', 'Unknown Category.' );
return $this->index();
}
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'reviews.admin.categoryEdit', $category );
}
if ( ! Forms::check( 'categoryEdit' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'reviews.admin.categoryEdit', $category );
}
$result = self::$categories->update(
$id,
Input::post( 'name' ),
Input::post( 'slug' ),
);
if ( $result ) {
Issues::add( 'success', 'Your review category has been updated.' );
return $this->index();
}
Issues::add( 'error', [ 'There was an unknown error submitting your data.' => Check::userErrors() ] );
Views::view( 'reviews.admin.categoryEdit', $category );
}
public function categoryDelete( $id = null ) {
if ( self::$categories->delete( $id ) ) {
Issues::add( 'success', 'review category deleted' );
} else {
Issues::add( 'error', 'There was an error with your request.' );
}
$this->index();
}
public function reviewView( $id = null ) {
Views::view( 'reviews.admin.review', self::$reviews->findById( $id ) );
}
public function reviewApprove( $id = null ) {
if ( self::$reviews->approve( $id ) ) {
Issues::add( 'success', 'review approved' );
} else {
Issues::add( 'error', 'There was an error with your request.' );
}
$this->index();
}
public function reviewHide( $id = null ) {
if ( self::$reviews->hide( $id ) ) {
Issues::add( 'success', 'review hidden' );
} else {
Issues::add( 'error', 'There was an error with your request.' );
}
$this->index();
}
public function reviewDelete( $id = null ) {
if ( self::$reviews->delete( $id ) ) {
Issues::add( 'success', 'review deleted' );
} else {
Issues::add( 'error', 'There was an error with your request.' );
}
$this->index();
}
}

View File

@ -0,0 +1,156 @@
<?php
/**
* app/plugins/reviews/controllers/reviews.php
*
* This is the reviews controller.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Controllers;
use TheTempusProject\Hermes\Functions\Redirect;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Session;
use TheTempusProject\Houdini\Classes\Issues;
use TheTempusProject\Houdini\Classes\Views;
use TheTempusProject\Classes\Controller;
use TheTempusProject\Classes\Forms;
use TheTempusProject\Models\Review;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Houdini\Classes\Components;
use TheTempusProject\Houdini\Classes\Template;
use TheTempusProject\Models\ReviewCategory;
use TheTempusProject\Houdini\Classes\Forms as HoudiniForms;
class Reviews extends Controller {
protected static $reviews;
protected static $categories;
public function __construct() {
self::$title = 'Reviews - {SITENAME}';
self::$pageDescription = 'This page allows you to add a new product review or update your existing reviews.';
if ( ! App::$isLoggedIn ) {
Session::flash( 'notice', 'You must be logged in to review products.' );
return Redirect::home();
}
parent::__construct();
self::$reviews = new Review;
self::$categories = new ReviewCategory;
Components::append( 'TEMPLATE_JS_INCLUDES', Template::parse('<script language="JavaScript" crossorigin="anonymous" type="text/javascript" src="{ROOT_URL}app/plugins/reviews/js/reviews.js"></script>' ) );
Components::append( 'TEMPLATE_CSS_INCLUDES', Template::parse('<link rel="stylesheet" href="{ROOT_URL}app/plugins/reviews/css/reviews.css">') );
}
public function index() {
Views::view( 'reviews.list', self::$reviews->byUser() );
}
public function review( $slug = null ) {
$category = self::$categories->findBySlug( $slug );
if ( ! $category ) {
$categories = self::$categories->simpleUnreviewed();
if ( empty( $categories ) ) {
Session::flash( 'notice', 'There are no additional products to review at this time.' );
Redirect::to( 'reviews/index' );
}
$selectedCategory = '0';
$reviewCategorySelect = HoudiniForms::getSelectHtml(
'review_category_id',
$categories,
$selectedCategory,
);
Components::set( 'reviewCategorySelect', $reviewCategorySelect );
} else {
$selectedCategory = $category->ID;
Components::set(
'reviewCategorySelect',
'<input type="hidden" name="review_category_id" id="review_category_id" value="' . $selectedCategory . '">'
);
}
if ( ! Input::exists('submit') ) {
return Views::view( 'reviews.create' );
}
if ( ! Forms::check( 'createReview' ) ) {
Issues::add( 'error', [ 'There was an error with your review.' => Check::userErrors() ] );
return Views::view( 'reviews.create' );
}
$result = self::$reviews->create( Input::post('title'), Input::post('rating'), Input::post('review'), Input::post('review_category_id') );
if ( ! empty( $result ) ) {
Session::flash( 'success', 'Your review has been received.' );
Redirect::to( 'reviews/index' );
} else {
Issues::add( 'error', 'There was an unresolved error while submitting your review.' );
return Views::view( 'reviews.create' );
}
}
public function view( $id = null ) {
$review = $this->confirmOwner( $id );
Views::view( 'reviews.view', $review );
}
public function edit( $id = null ) {
$review = $this->confirmOwner( $id );
if ( ! Input::exists( 'submit' ) ) {
return Views::view( 'reviews.edit', $review );
}
if ( ! Forms::check( 'reviewEditPublic' ) ) {
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
return Views::view( 'reviews.edit', $review );
}
$result = self::$reviews->update(
$id,
Input::post('title'),
Input::post('rating'),
Input::post('review')
);
if ( $result ) {
Session::flash( 'success', 'Your review has been updated.' );
return Redirect::to( 'reviews/index' );
}
Issues::add( 'error', [ 'There was an error with your request.' => Check::userErrors() ] );
Views::view( 'reviews.edit', $review );
}
public function delete( $id = null ) {
$this->confirmOwner( $id );
if ( self::$reviews->delete( $id ) ) {
Session::flash( 'success', 'Review deleted' );
} else {
Session::flash( 'error', 'There was an error with your request.' );
}
return Redirect::to( 'reviews/index' );
}
private function confirmOwner( $id ) {
if ( ! App::$isLoggedIn ) {
Session::flash( 'error', 'You must be logged in to review products.' );
return Redirect::home();
}
if ( !Check::id( $id ) ) {
Session::flash( 'error', 'Unknown Review' );
return Redirect::to( 'reviews/index' );
}
$review = self::$reviews->findById( $id );
if ( empty( $review ) ) {
Session::flash( 'error', 'Unknown Review' );
return Redirect::to( 'reviews/index' );
}
if ( App::$activeUser->ID != $review->createdBy ) {
Session::flash( 'error', 'Unknown Review' );
return Redirect::to( 'reviews/index' );
}
return $review;
}
}

View File

@ -0,0 +1,9 @@
.star-rating .fa-star {
font-size: 24px;
color: grey;
cursor: pointer;
}
.star-rating .fa-star.checked {
color: gold;
}

View File

@ -0,0 +1,109 @@
<?php
/**
* app/plugins/reviews/forms.php
*
* This houses all of the form checking functions for this plugin.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins\Reviews;
use TheTempusProject\Bedrock\Functions\Input;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Classes\Forms;
class ReviewForms extends Forms {
/**
* Adds these functions to the form list.
*/
public function __construct() {
self::addHandler( 'createReview', __CLASS__, 'createReview' );
self::addHandler( 'editReview', __CLASS__, 'editReview' );
self::addHandler( 'categoryCreate', __CLASS__, 'categoryCreate' );
self::addHandler( 'categoryEdit', __CLASS__, 'categoryEdit' );
self::addHandler( 'reviewEditPublic', __CLASS__, 'reviewEditPublic' );
}
/**
* Validates the createReview form.
*
* @return {bool}
*/
public static function createReview() {
if ( ! Input::exists( 'review' ) ) {
Check::addUserError( 'You must provide a review.' );
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must provide a title.' );
return false;
}
if ( ! Input::exists( 'rating' ) ) {
Check::addUserError( 'You must provide a rating.' );
return false;
}
if ( ! Input::exists( 'review_category_id' ) ) {
Check::addUserError( 'You must provide a review_category_id.' );
return false;
}
return true;
}
public static function editReview() {
if ( ! Input::exists( 'review' ) ) {
Check::addUserError( 'You must provide a review.' );
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must provide a title.' );
return false;
}
if ( ! Input::exists( 'rating' ) ) {
Check::addUserError( 'You must provide a rating.' );
return false;
}
return true;
}
public static function categoryCreate() {
if ( ! Input::exists( 'name' ) ) {
Check::addUserError( 'You must provide a name.' );
return false;
}
if ( ! Input::exists( 'slug' ) ) {
Check::addUserError( 'You must provide a slug.' );
return false;
}
return true;
}
public static function categoryEdit() {
if ( ! Input::exists( 'name' ) ) {
Check::addUserError( 'You must provide a name.' );
return false;
}
if ( ! Input::exists( 'slug' ) ) {
Check::addUserError( 'You must provide a slug.' );
return false;
}
return true;
}
public static function reviewEditPublic() {
if ( ! Input::exists( 'review' ) ) {
Check::addUserError( 'You must provide a review.' );
return false;
}
if ( ! Input::exists( 'title' ) ) {
Check::addUserError( 'You must provide a title.' );
return false;
}
if ( ! Input::exists( 'rating' ) ) {
Check::addUserError( 'You must provide a rating.' );
return false;
}
return true;
}
}
new ReviewForms;

View File

@ -0,0 +1,20 @@
$(document).ready(function() {
var $star_rating = $('.star-rating .fa-star');
var SetRatingStar = function() {
return $star_rating.each(function() {
if (parseInt($(this).siblings('input.rating-value').val()) >= parseInt($(this).data('rating'))) {
return $(this).addClass('checked');
} else {
return $(this).removeClass('checked');
}
});
};
$star_rating.on('click', function() {
$(this).siblings('input.rating-value').val($(this).data('rating'));
return SetRatingStar();
});
SetRatingStar();
});

View File

@ -0,0 +1,164 @@
<?php
/**
* app/plugins/reviews/models/review.php
*
* This class is used for the manipulation of the reviews database table.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Plugins\Reviews as Plugin;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Canary\Classes\CustomException;
class Review extends DatabaseModel {
public $tableName = 'reviews';
public $databaseMatrix = [
[ 'review_category_id', 'int', '11' ],
[ 'title', 'varchar', '128' ],
[ 'rating', 'int', '1' ],
[ 'review', 'text', '' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
[ 'approvedAt', 'int', '11' ],
[ 'approvedBy', 'int', '11' ],
];
public $plugin;
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
$this->plugin = new Plugin;
}
public function create( $title, $rating, $review, $review_category_id = '0' ) {
if ( ! $this->plugin->checkEnabled() ) {
Debug::info( 'Reviews are disabled in the config.' );
return false;
}
$fields = [
'title' => $title,
'rating' => $rating,
'review' => $review,
'review_category_id' => $review_category_id,
'createdAt' => time(),
'createdBy' => App::$activeUser->ID,
];
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
Debug::info( 'Reviews::create - failed to insert to db' );
return false;
}
return self::$db->lastId();
}
public function update( $id, $title, $rating, $review, $review_category_id = null ) {
if ( ! $this->plugin->checkEnabled() ) {
Debug::info( 'Reviews are disabled in the config.' );
return false;
}
$fields = [
'title' => $title,
'rating' => $rating,
'review' => $review
];
if ( ! empty( $review_category_id ) ) {
$fields['review_category_id'] = $review_category_id;
}
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'reviewUpdate' );
Debug::error( "Review: $id not updated: $fields" );
return false;
}
return true;
}
public function approve( $ID ) {
if ( !Check::id( $ID ) ) {
Debug::info( 'Review Categories: illegal ID.' );
return false;
}
$fields = [
'approvedAt' => time(),
'approvedBy' => App::$activeUser->ID,
];
if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
new CustomException( $this->tableName );
Debug::error( "Review Categories: $ID Approved: $fields" );
return false;
}
return true;
}
public function hide( $ID ) {
// if ( !Check::id( $ID ) ) {
// Debug::info( 'Review Categories: illegal ID.' );
// return false;
// }
// $fields = [
// 'approvedAt' => null,
// 'approvedBy' => null,
// ];
// if ( !self::$db->update( $this->tableName, $ID, $fields ) ) {
// new CustomException( $this->tableName );
// Debug::error( "Review Categories: $ID not Approved: $fields" );
// return false;
// }
return true;
}
public function byUser( $limit = null ) {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
if ( empty( $limit ) ) {
$reviews = self::$db->get( $this->tableName, $whereClause );
} else {
$reviews = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$reviews->count() ) {
Debug::info( 'No Reviews found.' );
return false;
}
return $this->filter( $reviews->results() );
}
public function reviewedCategoriesByUser() {
$whereClause = ['createdBy', '=', App::$activeUser->ID];
$reviews = self::$db->action( 'SELECT ID,review_category_id', $this->tableName, $whereClause );
if ( !$reviews->count() ) {
Debug::info( 'No Reviews found.' );
return false;
}
$categoryIds = [];
foreach ($reviews->results() as $key => $result) {
if ( ! in_array( $result->review_category_id, $categoryIds ) ) {
$categoryIds[] = $result->review_category_id;
}
}
return $categoryIds;
}
public function byCategory( $id, $limit = null ) {
$whereClause = [ 'review_category_id', '=', $id ];
if ( empty( $limit ) ) {
$reviews = self::$db->get( $this->tableName, $whereClause );
} else {
$reviews = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$reviews->count() ) {
Debug::info( 'No Reviews found.' );
return false;
}
return $this->filter( $reviews->results() );
}
}

View File

@ -0,0 +1,138 @@
<?php
/**
* app/plugins/reviews/models/review_category.php
*
* This class is used for the manipulation of the review_categories database table.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Models;
use TheTempusProject\Bedrock\Classes\Config;
use TheTempusProject\Bedrock\Functions\Check;
use TheTempusProject\Canary\Bin\Canary as Debug;
use TheTempusProject\Classes\DatabaseModel;
use TheTempusProject\Plugins\Reviews as Plugin;
use TheTempusProject\Models\Review;
use TheTempusProject\TheTempusProject as App;
use TheTempusProject\Canary\Classes\CustomException;
class ReviewCategory extends DatabaseModel {
public $tableName = 'review_categories';
public $databaseMatrix = [
[ 'name', 'varchar', '128' ],
[ 'slug', 'varchar', '64' ],
[ 'createdBy', 'int', '11' ],
[ 'createdAt', 'int', '11' ],
];
public $plugin;
/**
* The model constructor.
*/
public function __construct() {
parent::__construct();
$this->plugin = new Plugin;
}
public function create( $name, $slug ) {
if ( ! $this->plugin->checkEnabled() ) {
Debug::info( 'Reviews are disabled in the config.' );
return false;
}
if ( !Check::dataTitle( $slug ) ) {
Debug::info( 'Review Categories: illegal title.' );
return false;
}
$fields = [
'name' => $name,
'slug' => $slug,
'createdAt' => time(),
'createdBy' => App::$activeUser->ID,
];
if ( ! self::$db->insert( $this->tableName, $fields ) ) {
Debug::info( 'ReviewCategories::create - failed to insert to db' );
return false;
}
return self::$db->lastId();
}
public function update( $id, $name, $slug ) {
if ( ! $this->plugin->checkEnabled() ) {
Debug::info( 'Reviews are disabled in the config.' );
return false;
}
if ( !Check::dataTitle( $slug ) ) {
Debug::info( 'Review Categories: illegal title.' );
return false;
}
$fields = [
'name' => $name,
'slug' => $slug,
];
if ( !self::$db->update( $this->tableName, $id, $fields ) ) {
new CustomException( 'reviewCategoryUpdate' );
Debug::error( "Review Categories: $id not updated: $fields" );
return false;
}
return true;
}
public function findBySlug( $slug, $limit = null ) {
$whereClause = [ 'slug', '=', $slug ];
if ( empty( $limit ) ) {
$categories = self::$db->get( $this->tableName, $whereClause );
} else {
$categories = self::$db->get( $this->tableName, $whereClause, 'ID', 'DESC', [0, $limit] );
}
if ( !$categories->count() ) {
Debug::info( 'No categories found.' );
return false;
}
return $this->filter( $categories->first() );
}
public function simple() {
$categories = self::$db->get( $this->tableName, '*' );
if ( !$categories->count() ) {
Debug::warn( 'Could not find any categories' );
return false;
}
$categories = $categories->results();
$out = [];
foreach ( $categories as &$category ) {
$out[ $category->name ] = $category->ID;
}
return $out;
}
public function simpleUnreviewed() {
$categories = self::$db->get( $this->tableName, '*' );
if ( !$categories->count() ) {
Debug::warn( 'Could not find any categories' );
return false;
}
$categories = $categories->results();
$review = new Review;
$reviews = $review->reviewedCategoriesByUser();
$out = [];
foreach ( $categories as &$category ) {
if ( ! empty( $reviews) && in_array( $category->ID, $reviews ) ) {
continue;
}
$out[ $category->name ] = $category->ID;
}
return $out;
}
}

View File

@ -0,0 +1,51 @@
<?php
/**
* app/plugins/reviews/plugin.php
*
* This houses all of the main plugin info and functionality.
*
* @package TP Reviews
* @version 3.0
* @author Joey Kimsey <Joey@thetempusproject.com>
* @link https://TheTempusProject.com
* @license https://opensource.org/licenses/MIT [MIT LICENSE]
*/
namespace TheTempusProject\Plugins;
use TheTempusProject\Classes\Plugin;
class Reviews extends Plugin {
public $pluginName = 'TP Reviews';
public $pluginAuthor = 'JoeyK';
public $pluginWebsite = 'https://TheTempusProject.com';
public $modelVersion = '1.0';
public $pluginVersion = '3.0';
public $pluginDescription = 'A simple plugin which adds a site wide review system.';
public $permissionMatrix = [
'review' => [
'pretty' => 'Can create reviews',
'default' => false,
],
'createReviewCategory' => [
'pretty' => 'Can create review categories',
'default' => false,
],
];
public $admin_links = [
[
'text' => '<i class="fa fa-fw fa-copy"></i> Reviews',
'url' => '{ROOT_URL}admin/reviews',
],
];
public $contact_footer_links = [
[
'text' => 'Reviews',
'url' => '{ROOT_URL}reviews/index/',
'filter' => 'loggedin',
],
];
}
// need a setting to allow reviewing a category from the dropdown
// if disabled, "I'm sorry but reviews are invite only. If you have been asked to review a product, double check the link and make sure its been entered correctly
// if you have not been invited to review a product, please feel free to leave any feedback in the feedback section.

View File

@ -0,0 +1,42 @@
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
{ADMIN_BREADCRUMBS}
<div class="card shadow">
<!-- Card Header -->
<div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">Review Category: {name}</h3>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row align-items-center">
<!-- Details -->
<table class="table table-borderless">
<tbody>
<tr>
<th scope="row">Name:</th>
<td>{name}</td>
</tr>
<tr>
<th scope="row">Slug:</th>
<td>{slug}</td>
</tr>
<tr>
<th scope="row">Created:</th>
<td>{DTC}{createdAt}{/DTC}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Admin Controls -->
<div class="card-footer text-center">
<a href="{ROOT_URL}admin/reviews/categoryEdit/{ID}" class="btn btn-md btn-warning" role="button"><i class="fa fa-fw fa-pencil"></i></a>
<a href="{ROOT_URL}admin/reviews/categoryDelete/{ID}" class="btn btn-md btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,35 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Add Review Category</legend>
<hr>
{ADMIN_BREADCRUMBS}
<form method="post">
<fieldset>
<!-- Name -->
<div class="mb-3 row">
<label for="name" class="col-lg-6 col-form-label text-end">Name:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="name" id="name" required>
</div>
</div>
<!-- Slug -->
<div class="mb-3 row">
<label for="slug" class="col-lg-6 col-form-label text-end">Slug:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="slug" id="slug" aria-describedby="slugHelp" required>
<small id="slugHelp" class="form-text text-muted">
Public links would be {ROOT_URL}reviews/YOUR_SLUG_HERE
</small>
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Create</button>
</div>
</fieldset>
</form>
</div>

View File

@ -0,0 +1,35 @@
<div class="context-main-bg context-main p-3">
<legend class="text-center">Edit Review Category</legend>
<hr>
{ADMIN_BREADCRUMBS}
<form method="post">
<fieldset>
<!-- Name -->
<div class="mb-3 row">
<label for="name" class="col-lg-6 col-form-label text-end">Name:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="name" id="name" value="{name}" required>
</div>
</div>
<!-- Slug -->
<div class="mb-3 row">
<label for="slug" class="col-lg-6 col-form-label text-end">Slug:</label>
<div class="col-lg-2">
<input type="text" class="form-control" name="slug" id="slug" aria-describedby="slugHelp" value="{slug}" required>
<small id="slugHelp" class="form-text text-muted">
Public links would be {ROOT_URL}reviews/YOUR_SLUG_HERE
</small>
</div>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg">Create</button>
</div>
</fieldset>
</form>
</div>

View File

@ -0,0 +1,33 @@
<legend>Review Categories</legend>
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 30%">Name</th>
<th style="width: 30%">Slug</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td align="center">{ID}</td>
<td>{name}</td>
<td>{slug}</td>
<td><a href="{ROOT_URL}admin/reviews/categoryView/{ID}" class="btn btn-sm btn-primary" role="button"><i class="fa fa-fw fa-info-circle"></i></a></td>
<td><a href="{ROOT_URL}admin/reviews/categoryEdit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}admin/reviews/categoryDelete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}admin/reviews/categoryCreate" class="btn btn-sm btn-primary" role="button">Create</a>

View File

@ -0,0 +1,9 @@
<div class="row">
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
{reviews}
</div>
<div class="col-xlg-6 col-lg-6 col-md-6 col-sm-6 col-xs-6">
{reviewCategories}
</div>
</div>

View File

@ -0,0 +1,49 @@
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
{ADMIN_BREADCRUMBS}
<div class="card shadow">
<!-- Card Header -->
<div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">Review: {title}</h3>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row align-items-center">
<!-- Details -->
<table class="table table-borderless">
<tbody>
<tr>
<th scope="row">Title:</th>
<td>{title}</td>
</tr>
<tr>
<th scope="row">Rating:</th>
<td>{rating}</td>
</tr>
<tr>
<th scope="row">Created:</th>
<td>{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<th scope="row" colspan="2">Review:</th>
</tr>
<tr>
<td colspan="2">{review}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Admin Controls -->
<div class="card-footer text-center">
<a href="{ROOT_URL}admin/reviews/reviewApprove/{ID}" class="btn btn-sm btn-success" role="button"><i class="fa fa-fw fa-info-circle"></i></a>
<a href="{ROOT_URL}admin/reviews/reviewHide/{ID}" class="btn btn-sm btn-info" role="button"><i class="fa fa-fw fa-eye-closed"></i></a>
<a href="{ROOT_URL}admin/reviews/reviewDelete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,32 @@
<legend>Reviews</legend>
<table class="table table-striped">
<thead>
<tr>
<th style="width: 10%">ID</th>
<th style="width: 30%">Title</th>
<th style="width: 30%">Rating</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td align="center">{ID}</td>
<td><a href="{ROOT_URL}admin/reviews/reviewView/{ID}" class="btn btn-sm btn-primary" role="button">{title}</a></td>
<td align="center">{rating}</td>
<td><a href="{ROOT_URL}admin/reviews/reviewApprove/{ID}" class="btn btn-sm btn-success" role="button"><i class="fa fa-fw fa-check"></i></a></td>
<td><a href="{ROOT_URL}admin/reviews/reviewHide/{ID}" class="btn btn-sm btn-info" role="button"><i class="fa fa-fw fa-eye-closed"></i></a></td>
<td><a href="{ROOT_URL}admin/reviews/reviewDelete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td align="center" colspan="6">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>

View File

@ -0,0 +1,49 @@
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
{ADMIN_BREADCRUMBS}
<div class="card shadow">
<!-- Card Header -->
<div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">Review: {title}</h3>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row align-items-center">
<!-- Details -->
<table class="table table-borderless">
<tbody>
<tr>
<th scope="row">Title:</th>
<td>{title}</td>
</tr>
<tr>
<th scope="row">Rating:</th>
<td>{rating}</td>
</tr>
<tr>
<th scope="row">Created:</th>
<td>{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<th scope="row" colspan="2">Review:</th>
</tr>
<tr>
<td colspan="2">{review}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Admin Controls -->
<div class="card-footer text-center">
<a href="{ROOT_URL}admin/reviews/reviewApprove/{ID}" class="btn btn-sm btn-success" role="button"><i class="fa fa-fw fa-info-circle"></i></a>
<a href="{ROOT_URL}admin/reviews/reviewHide/{ID}" class="btn btn-sm btn-info" role="button"><i class="fa fa-fw fa-eye-closed"></i></a>
<a href="{ROOT_URL}admin/reviews/reviewDelete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,52 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm mb-5 context-main-bg mt-4 container">
<h2 class="text-center mb-4">Share a Review</h2>
<hr>
<p>We thank you for for taking the time to review our products. We do not edit or modify reviews in any way. You, as the customer have the ability to modify your own reviews.</p>
<p>We read each and every review. You and the admin team both have the ability to comment on reviews privately. Neither your reviews or comments will be publicly shared without your permission.</p>
<form id="review-form" method="post">
<!-- Review Category -->
<div class="mb-3">
<label for="review_category_id" class="form-label">Review Category:</label>
{reviewCategorySelect}
</div>
<!-- Rating -->
<div class="mb-3">
<label for="star-rating" class="form-label">Rating:</label>
<div class="star-rating">
<span class="fa fa-star" data-rating="1"></span>
<span class="fa fa-star" data-rating="2"></span>
<span class="fa fa-star" data-rating="3"></span>
<span class="fa fa-star" data-rating="4"></span>
<span class="fa fa-star" data-rating="5"></span>
<input type="hidden" name="rating" class="rating-value" value="0">
</div>
</div>
<!-- Review Title -->
<div class="mb-3">
<label for="title" class="form-label">Review Title:</label>
<input type="text" class="form-control" id="title" name="title" aria-describedby="titleHelp" required>
<small id="titleHelp" class="form-text text-muted">
No need to overthink it, something as simple as "My Review" is fine.
</small>
</div>
<!-- Review -->
<div class="mb-3">
<label for="review" class="form-label">Your Review:</label>
<textarea class="form-control" name="review" id="review" rows="5" maxlength="2000" aria-describedby="reviewHelp" required></textarea>
<small id="reviewHelp" class="form-text text-muted">
(max: 2000 characters)
</small>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg atb-green-bg">Submit</button>
</div>
</form>
</div>

View File

@ -0,0 +1,44 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm mb-5 context-main-bg mt-4 container">
<h2 class="text-center mb-4">Edit Your Review</h2>
<hr>
<form id="review-form" method="post">
<!-- Review Title -->
<div class="mb-3">
<label for="title" class="form-label">Review Title:</label>
<input type="text" class="form-control" id="title" name="title" aria-describedby="titleHelp" value="{title}" required>
<small id="titleHelp" class="form-text text-muted">
No need to overthink it, something as simple as "My Review" is fine.
</small>
</div>
<!-- Rating -->
<div class="mb-3">
<label for="star-rating" class="form-label">Rating:</label>
<div class="star-rating">
<span class="fa fa-star" data-rating="1"></span>
<span class="fa fa-star" data-rating="2"></span>
<span class="fa fa-star" data-rating="3"></span>
<span class="fa fa-star" data-rating="4"></span>
<span class="fa fa-star" data-rating="5"></span>
<input type="hidden" name="rating" class="rating-value" value="{rating}">
</div>
</div>
<!-- Review -->
<div class="mb-3">
<label for="review" class="form-label">Your Review:</label>
<textarea class="form-control" name="review" id="review" rows="5" maxlength="2000" aria-describedby="reviewHelp" required>{review}</textarea>
<small id="reviewHelp" class="form-text text-muted">
(max: 2000 characters)
</small>
</div>
<!-- Hidden Token -->
<input type="hidden" name="token" value="{TOKEN}">
<!-- Submit Button -->
<div class="text-center">
<button type="submit" name="submit" value="submit" class="btn btn-primary btn-lg atb-green-bg">Submit</button>
</div>
</form>
</div>

View File

@ -0,0 +1,38 @@
<div class="col-8 mx-auto p-4 rounded shadow-sm mb-5 context-main-bg mt-4 context-main text-center">
<legend>Reviews</legend>
<hr>
<p>
Understanding the customer is a huge part of making products better. Whether its feedback that we are doing great, or we need work; the review allows users to share that with us.
</p>
<p>
On this page you can find <strong>your</strong> reviews to see any responses or make edits.
</p>
<table class="table context-main text-center">
<thead>
<tr>
<th style="width: 60%">Title</th>
<th style="width: 20%">Rating</th>
<th style="width: 10%"></th>
<th style="width: 10%"></th>
</tr>
</thead>
<tbody>
{LOOP}
<tr>
<td><a href="{ROOT_URL}reviews/view/{ID}" class="text-decoration-none atb-green" role="button">{title}</a></td>
<td>{rating}</td>
<td><a href="{ROOT_URL}reviews/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="fa fa-fw fa-pencil"></i></a></td>
<td><a href="{ROOT_URL}reviews/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a></td>
</tr>
{/LOOP}
{ALT}
<tr>
<td colspan="4">
No results to show.
</td>
</tr>
{/ALT}
</tbody>
</table>
<a href="{ROOT_URL}reviews/review" class="btn btn-md atb-green-bg" role="button">Add Review</a>
</div>

View File

@ -0,0 +1,47 @@
<div class="container py-4">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card shadow">
<!-- Card Header -->
<div class="card-header text-center bg-dark text-white">
<h3 class="card-title mb-0">Review: {title}</h3>
</div>
<!-- Card Body -->
<div class="card-body">
<div class="row align-items-center">
<!-- Details -->
<table class="table table-borderless">
<tbody>
<tr>
<th scope="row">Title:</th>
<td>{title}</td>
</tr>
<tr>
<th scope="row">Rating:</th>
<td>{rating}</td>
</tr>
<tr>
<th scope="row">Created:</th>
<td>{DTC}{createdAt}{/DTC}</td>
</tr>
<tr>
<th scope="row" colspan="2">Review:</th>
</tr>
<tr>
<td colspan="2">{review}</td>
</tr>
</tbody>
</table>
</div>
</div>
<!-- Admin Controls -->
<div class="card-footer text-center">
<a href="{ROOT_URL}reviews/edit/{ID}" class="btn btn-sm btn-warning" role="button"><i class="fa fa-fw fa-pencil"></i></a>
<a href="{ROOT_URL}reviews/delete/{ID}" class="btn btn-sm btn-danger" role="button"><i class="fa fa-fw fa-trash"></i></a>
</div>
</div>
</div>
</div>
</div>