179 lines
5.5 KiB
Dart
179 lines
5.5 KiB
Dart
/// Providers: Reviews
|
|
///
|
|
/// Riverpod providers for review management.
|
|
library;
|
|
|
|
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
|
import 'package:worker/core/network/dio_client.dart';
|
|
import 'package:worker/features/reviews/data/datasources/reviews_remote_datasource.dart';
|
|
import 'package:worker/features/reviews/data/repositories/reviews_repository_impl.dart';
|
|
import 'package:worker/features/reviews/domain/entities/review.dart';
|
|
import 'package:worker/features/reviews/domain/entities/review_statistics.dart';
|
|
import 'package:worker/features/reviews/domain/repositories/reviews_repository.dart';
|
|
import 'package:worker/features/reviews/domain/usecases/delete_review.dart';
|
|
import 'package:worker/features/reviews/domain/usecases/get_product_reviews.dart';
|
|
import 'package:worker/features/reviews/domain/usecases/submit_review.dart';
|
|
|
|
part 'reviews_provider.g.dart';
|
|
|
|
// ============================================================================
|
|
// Data Layer Providers
|
|
// ============================================================================
|
|
|
|
/// Provider for reviews remote data source
|
|
@riverpod
|
|
Future<ReviewsRemoteDataSource> reviewsRemoteDataSource(
|
|
Ref ref,
|
|
) async {
|
|
final dioClient = await ref.watch(dioClientProvider.future);
|
|
return ReviewsRemoteDataSourceImpl(dioClient);
|
|
}
|
|
|
|
/// Provider for reviews repository
|
|
@riverpod
|
|
Future<ReviewsRepository> reviewsRepository(Ref ref) async {
|
|
final remoteDataSource = await ref.watch(reviewsRemoteDataSourceProvider.future);
|
|
return ReviewsRepositoryImpl(remoteDataSource);
|
|
}
|
|
|
|
// ============================================================================
|
|
// Use Case Providers
|
|
// ============================================================================
|
|
|
|
/// Provider for get product reviews use case
|
|
@riverpod
|
|
Future<GetProductReviews> getProductReviews(Ref ref) async {
|
|
final repository = await ref.watch(reviewsRepositoryProvider.future);
|
|
return GetProductReviews(repository);
|
|
}
|
|
|
|
/// Provider for submit review use case
|
|
@riverpod
|
|
Future<SubmitReview> submitReview(Ref ref) async {
|
|
final repository = await ref.watch(reviewsRepositoryProvider.future);
|
|
return SubmitReview(repository);
|
|
}
|
|
|
|
/// Provider for delete review use case
|
|
@riverpod
|
|
Future<DeleteReview> deleteReview(Ref ref) async {
|
|
final repository = await ref.watch(reviewsRepositoryProvider.future);
|
|
return DeleteReview(repository);
|
|
}
|
|
|
|
// ============================================================================
|
|
// State Providers
|
|
// ============================================================================
|
|
|
|
/// Provider for fetching reviews for a specific product
|
|
///
|
|
/// This is a family provider that takes a product ID and returns
|
|
/// the list of reviews for that product.
|
|
///
|
|
/// Usage:
|
|
/// ```dart
|
|
/// final reviewsAsync = ref.watch(productReviewsProvider('PRODUCT_ID'));
|
|
/// ```
|
|
@riverpod
|
|
Future<List<Review>> productReviews(
|
|
Ref ref,
|
|
String itemId,
|
|
) async {
|
|
final getProductReviewsUseCase = await ref.watch(getProductReviewsProvider.future);
|
|
|
|
return await getProductReviewsUseCase(
|
|
itemId: itemId,
|
|
limitPageLength: 50, // Fetch more reviews
|
|
limitStart: 0,
|
|
);
|
|
}
|
|
|
|
/// Provider for review statistics (from API)
|
|
///
|
|
/// Gets statistics directly from API including:
|
|
/// - Total feedback count
|
|
/// - Average rating (0-5 scale, already calculated by server)
|
|
///
|
|
/// This is more efficient than calculating client-side
|
|
@riverpod
|
|
Future<ReviewStatistics> productReviewStatistics(
|
|
Ref ref,
|
|
String itemId,
|
|
) async {
|
|
final repository = await ref.watch(reviewsRepositoryProvider.future);
|
|
return await repository.getProductReviewStatistics(itemId: itemId);
|
|
}
|
|
|
|
/// Provider for average rating (convenience wrapper)
|
|
///
|
|
/// Gets the average rating from API statistics
|
|
/// Returns 0.0 if there are no reviews.
|
|
@riverpod
|
|
Future<double> productAverageRating(
|
|
Ref ref,
|
|
String itemId,
|
|
) async {
|
|
final stats = await ref.watch(productReviewStatisticsProvider(itemId).future);
|
|
return stats.averageRating;
|
|
}
|
|
|
|
/// Provider for counting reviews (convenience wrapper)
|
|
///
|
|
/// Gets the total count from API statistics
|
|
@riverpod
|
|
Future<int> productReviewCount(
|
|
Ref ref,
|
|
String itemId,
|
|
) async {
|
|
final stats = await ref.watch(productReviewStatisticsProvider(itemId).future);
|
|
return stats.totalFeedback;
|
|
}
|
|
|
|
/// Provider for checking if user can submit a review
|
|
///
|
|
/// This can be extended to check if user has already reviewed
|
|
/// the product and enforce one-review-per-user policy.
|
|
///
|
|
/// For now, it always returns true.
|
|
@riverpod
|
|
Future<bool> canSubmitReview(
|
|
Ref ref,
|
|
String itemId,
|
|
) async {
|
|
// TODO: Implement logic to check if user already reviewed this product
|
|
// This would require user email from auth state
|
|
return true;
|
|
}
|
|
|
|
// ============================================================================
|
|
// Helper Functions
|
|
// ============================================================================
|
|
|
|
/// Convert star rating (1-5) to API rating (0-1)
|
|
///
|
|
/// Example:
|
|
/// - 1 star = 0.2
|
|
/// - 2 stars = 0.4
|
|
/// - 3 stars = 0.6
|
|
/// - 4 stars = 0.8
|
|
/// - 5 stars = 1.0
|
|
double starsToApiRating(int stars) {
|
|
if (stars < 1 || stars > 5) {
|
|
throw ArgumentError('Stars must be between 1 and 5. Got: $stars');
|
|
}
|
|
return stars / 5.0;
|
|
}
|
|
|
|
/// Convert API rating (0-1) to star rating (1-5)
|
|
///
|
|
/// Example:
|
|
/// - 0.2 = 1 star
|
|
/// - 0.5 = 2.5 stars (rounded to 3)
|
|
/// - 1.0 = 5 stars
|
|
int apiRatingToStars(double rating) {
|
|
if (rating < 0 || rating > 1) {
|
|
throw ArgumentError('Rating must be between 0 and 1. Got: $rating');
|
|
}
|
|
return (rating * 5).round();
|
|
}
|