Files
Eventify-frontend/lib/features/reviews/widgets/star_rating_input.dart
Sicherhaven 1badeff966 feat: add complete review/rating system for events
New feature: Users can view, submit, and interact with event reviews.

Components added:
- ReviewModel, ReviewStatsModel, ReviewListResponse (models)
- ReviewService with getReviews, submitReview, markHelpful, flagReview
- StarRatingInput (interactive 5-star picker with labels)
- StarDisplay (read-only fractional star display)
- ReviewSummary (average rating + distribution bars)
- ReviewForm (star picker + comment field + submit/update)
- ReviewCard (avatar, timestamp, expandable comment, helpful/flag)
- ReviewSection (main container with pagination and state mgmt)

Integration:
- Added to LearnMoreScreen (both mobile and desktop layouts)
- Review API endpoints point to app.eventifyplus.com Node.js backend
- EventModel updated with averageRating/reviewCount fields

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 18:04:37 +05:30

57 lines
1.6 KiB
Dart

// lib/features/reviews/widgets/star_rating_input.dart
import 'package:flutter/material.dart';
class StarRatingInput extends StatelessWidget {
final int rating;
final ValueChanged<int> onRatingChanged;
final double starSize;
const StarRatingInput({
Key? key,
required this.rating,
required this.onRatingChanged,
this.starSize = 36,
}) : super(key: key);
static const _labels = ['', 'Poor', 'Fair', 'Good', 'Very Good', 'Excellent'];
static const _starGold = Color(0xFFFBBF24);
static const _starEmpty = Color(0xFFD1D5DB);
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
Row(
mainAxisSize: MainAxisSize.min,
children: List.generate(5, (i) {
final starIndex = i + 1;
return GestureDetector(
onTap: () => onRatingChanged(starIndex),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 2),
child: Icon(
starIndex <= rating ? Icons.star_rounded : Icons.star_outline_rounded,
size: starSize,
color: starIndex <= rating ? _starGold : _starEmpty,
),
),
);
}),
),
if (rating > 0) ...[
const SizedBox(height: 4),
Text(
_labels[rating],
style: TextStyle(
fontSize: 13,
fontWeight: FontWeight.w600,
color: _starGold,
),
),
],
],
);
}
}