Files
worker/docs/md/REVIEWS_QUICK_REFERENCE.md
Phuoc Nguyen 19d9a3dc2d update loaing
2025-12-02 18:09:20 +07:00

5.7 KiB

Reviews API - Quick Reference Guide

Rating Scale Conversion

Convert UI Stars to API Rating

// UI: 5 stars → API: 1.0
final apiRating = stars / 5.0;

Convert API Rating to UI Stars

// API: 0.8 → UI: 4 stars
final stars = (rating * 5).round();

Helper Functions (in reviews_provider.dart)

double apiRating = starsToApiRating(5);  // Returns 1.0
int stars = apiRatingToStars(0.8);       // Returns 4

Provider Usage

Get Reviews for Product

final reviewsAsync = ref.watch(productReviewsProvider(itemId));

reviewsAsync.when(
  data: (reviews) => /* show reviews */,
  loading: () => const CustomLoadingIndicator(),
  error: (error, stack) => /* show error */,
);

Get Average Rating

final avgRatingAsync = ref.watch(productAverageRatingProvider(itemId));

Get Review Count

final countAsync = ref.watch(productReviewCountProvider(itemId));

Submit Review

try {
  final submitUseCase = ref.read(submitReviewProvider);

  await submitUseCase(
    itemId: productId,
    rating: stars / 5.0,  // Convert stars to 0-1
    comment: comment,
  );

  // Refresh reviews
  ref.invalidate(productReviewsProvider(productId));
} catch (e) {
  // Handle error
}

Delete Review

try {
  final deleteUseCase = ref.read(deleteReviewProvider);

  await deleteUseCase(name: reviewId);

  // Refresh reviews
  ref.invalidate(productReviewsProvider(productId));
} catch (e) {
  // Handle error
}

API Endpoints

Get Reviews

POST /api/method/building_material.building_material.api.item_feedback.get_list

Body: {
  "limit_page_length": 10,
  "limit_start": 0,
  "item_id": "PRODUCT_ID"
}

Submit Review

POST /api/method/building_material.building_material.api.item_feedback.update

Body: {
  "item_id": "PRODUCT_ID",
  "rating": 0.8,        // 0-1 scale
  "comment": "Great!",
  "name": "REVIEW_ID"   // Optional, for updates
}

Delete Review

POST /api/method/building_material.building_material.api.item_feedback.delete

Body: {
  "name": "ITEM-PRODUCT_ID-user@email.com"
}

Review Entity

class Review {
  final String id;              // Review ID
  final String itemId;          // Product code
  final double rating;          // API rating (0-1)
  final String comment;         // Review text
  final String? reviewerName;   // Reviewer name
  final String? reviewerEmail;  // Reviewer email
  final DateTime? reviewDate;   // Review date

  // Convert to stars (0-5)
  int get starsRating => (rating * 5).round();
  double get starsRatingDecimal => rating * 5;
}

Error Handling

Common Exceptions

try {
  // API call
} on NoInternetException {
  // No internet connection
} on TimeoutException {
  // Request timeout
} on UnauthorizedException {
  // Session expired
} on ValidationException catch (e) {
  // Invalid data: e.message
} on NotFoundException {
  // Review not found
} on ServerException {
  // Server error (5xx)
} catch (e) {
  // Unknown error
}

Status Codes

  • 400: Bad Request - Invalid data
  • 401: Unauthorized - Session expired
  • 403: Forbidden - No permission
  • 404: Not Found - Review doesn't exist
  • 409: Conflict - Review already exists
  • 429: Too Many Requests - Rate limited
  • 500+: Server Error

Validation Rules

Rating

  • Must be 0-1 for API
  • Must be 1-5 for UI
  • Cannot be empty

Comment

  • Minimum: 20 characters
  • Maximum: 1000 characters
  • Cannot be empty or whitespace only

Date Formatting

String _formatDate(DateTime date) {
  final now = DateTime.now();
  final diff = now.difference(date);

  if (diff.inDays == 0) return 'Hôm nay';
  if (diff.inDays == 1) return 'Hôm qua';
  if (diff.inDays < 7) return '${diff.inDays} ngày trước';
  if (diff.inDays < 30) return '${(diff.inDays / 7).floor()} tuần trước';
  if (diff.inDays < 365) return '${(diff.inDays / 30).floor()} tháng trước';
  return '${(diff.inDays / 365).floor()} năm trước';
}

Review ID Format

ITEM-{item_id}-{user_email}

Examples:

  • ITEM-GIB20 G04-john@example.com
  • ITEM-Product123-user@company.com

Testing Checklist

  • Reviews load correctly
  • Rating conversion works (0-1 ↔ 1-5)
  • Submit review refreshes list
  • Average rating calculates correctly
  • Empty state shows when no reviews
  • Loading state shows during API calls
  • Error messages display correctly
  • Date formatting works
  • Star ratings display correctly
  • Form validation works

Common Issues

Issue: Reviews not loading

Solution: Check auth tokens (sid, csrf_token) are set

Issue: Rating conversion wrong

Solution: Always use stars / 5.0 for API, (rating * 5).round() for UI

Issue: Reviews not refreshing after submit

Solution: Use ref.invalidate(productReviewsProvider(itemId))

Issue: Provider not found error

Solution: Run dart run build_runner build to generate .g.dart files


File Locations

Domain:

  • lib/features/reviews/domain/entities/review.dart
  • lib/features/reviews/domain/repositories/reviews_repository.dart
  • lib/features/reviews/domain/usecases/*.dart

Data:

  • lib/features/reviews/data/models/review_model.dart
  • lib/features/reviews/data/datasources/reviews_remote_datasource.dart
  • lib/features/reviews/data/repositories/reviews_repository_impl.dart

Presentation:

  • lib/features/reviews/presentation/providers/reviews_provider.dart

Updated:

  • lib/features/products/presentation/widgets/product_detail/product_tabs_section.dart
  • lib/features/products/presentation/pages/write_review_page.dart
  • lib/core/constants/api_constants.dart