feat: Add complete reviews system with star ratings

 New Features:
- Reviews system with 1-5 star ratings
- User can add, edit, and delete their own reviews
- One review per product per user (DB constraint)
- Automatic average rating calculation
- Review count tracking
- Interactive star selection UI
- AJAX-powered review submission
- Responsive design for all devices

🗄️ Database:
- New 'reviews' table with full structure
- Added 'rating' and 'review_count' fields to products
- PostgreSQL triggers for automatic rating updates
- Database functions for rating calculations
- Indexes for performance optimization

📦 Backend (PHP):
- Review model with 15+ methods
- ReviewController with 5 actions
- Updated Product model to include ratings
- Updated ProductController to load reviews
- 5 new API endpoints

🎨 Frontend:
- Reviews list component (_reviews_list.php)
- Review form component (_review_form.php)
- Reviews sechow page
- Star ratings in catalog view
- Interactive JavaScript (200+ lines)
- Adaptive styles (400+ lines)

🔒 Security:
- Server-side authorization checks
- XSS protection (htmlspecialchars)
- SQL injection protection (PDO prepared)
- Input validation (client + server)
- Access control for review editing

📝 Modified Files:
- app/Models/Product.php - added rating fields to queries
- app/Controllers/ProductController.php - loads reviews
- app/Views/products/show.php - reviews section
- app/Views/products/catalog.php - star ratings
- config/routes.php - review endpoints
- public/style_for_cite.less - rating styles

🆕 New Files:
- app/Models/Review.php
- app/Controllers/ReviewController.php
- app/Views/products/_reviews_list.php
- app/Views/products/_review_form.php
This commit is contained in:
kirill.khorkov
2026-01-06 17:04:09 +03:00
parent 547c561ed0
commit a4092adf2e
17 changed files with 1646 additions and 59 deletions

View File

@@ -148,19 +148,65 @@ p, li, span {
.flex-center(10px);
width: 200px;
flex-shrink: 0;
user-select: none;
z-index: 1000;
&__menu {
.menu-base();
position: absolute;
top: 100%;
left: 0;
width: 250px;
background: white;
border-radius: 8px;
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
padding: 15px;
z-index: 10000;
margin-top: 5px;
display: none;
pointer-events: auto;
max-height: 400px;
overflow-y: auto;
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
padding: 8px 0;
cursor: pointer;
transition: color 0.3s;
border-bottom: 1px solid #f0f0f0;
list-style: none;
&:last-child { border-bottom: none; }
&:hover { color: @color-accent; }
a {
display: block;
color: #333;
text-decoration: none;
padding: 5px 0;
cursor: pointer;
width: 100%;
&:hover {
color: @color-accent;
}
}
&:hover {
a {
color: @color-accent;
}
}
}
}
&:hover &__menu { display: block; }
&:hover &__menu,
&.active &__menu {
display: block;
}
&.active {
background-color: #e8e8e8;
}
}
.search-box {
@@ -943,6 +989,67 @@ p, li, span {
align-items: center;
gap: 10px;
margin-bottom: 30px;
.stars {
display: flex;
gap: 2px;
.star {
font-size: 18px;
color: #ddd;
&.filled {
color: #ffc107;
}
}
}
span {
color: #666;
font-size: 14px;
}
}
// Global rating styles
.rating-stars {
display: flex;
gap: 2px;
.star {
font-size: 16px;
color: #ddd;
&.filled {
color: #ffc107;
}
}
}
// Review rating styles for product cards
.product-rating {
display: flex;
align-items: center;
gap: 8px;
margin-top: 5px;
.stars {
display: flex;
gap: 1px;
.star {
font-size: 14px;
color: #ddd;
&.filled {
color: #ffc107;
}
}
}
.rating-text {
font-size: 12px;
color: #666;
}
}
.product__color-selector {