266 lines
5.7 KiB
Markdown
266 lines
5.7 KiB
Markdown
# Reviews API - Quick Reference Guide
|
|
|
|
## Rating Scale Conversion
|
|
|
|
### Convert UI Stars to API Rating
|
|
```dart
|
|
// UI: 5 stars → API: 1.0
|
|
final apiRating = stars / 5.0;
|
|
```
|
|
|
|
### Convert API Rating to UI Stars
|
|
```dart
|
|
// API: 0.8 → UI: 4 stars
|
|
final stars = (rating * 5).round();
|
|
```
|
|
|
|
### Helper Functions (in reviews_provider.dart)
|
|
```dart
|
|
double apiRating = starsToApiRating(5); // Returns 1.0
|
|
int stars = apiRatingToStars(0.8); // Returns 4
|
|
```
|
|
|
|
---
|
|
|
|
## Provider Usage
|
|
|
|
### Get Reviews for Product
|
|
```dart
|
|
final reviewsAsync = ref.watch(productReviewsProvider(itemId));
|
|
|
|
reviewsAsync.when(
|
|
data: (reviews) => /* show reviews */,
|
|
loading: () => const CustomLoadingIndicator(),
|
|
error: (error, stack) => /* show error */,
|
|
);
|
|
```
|
|
|
|
### Get Average Rating
|
|
```dart
|
|
final avgRatingAsync = ref.watch(productAverageRatingProvider(itemId));
|
|
```
|
|
|
|
### Get Review Count
|
|
```dart
|
|
final countAsync = ref.watch(productReviewCountProvider(itemId));
|
|
```
|
|
|
|
### Submit Review
|
|
```dart
|
|
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
|
|
```dart
|
|
try {
|
|
final deleteUseCase = ref.read(deleteReviewProvider);
|
|
|
|
await deleteUseCase(name: reviewId);
|
|
|
|
// Refresh reviews
|
|
ref.invalidate(productReviewsProvider(productId));
|
|
} catch (e) {
|
|
// Handle error
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## API Endpoints
|
|
|
|
### Get Reviews
|
|
```dart
|
|
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
|
|
```dart
|
|
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
|
|
```dart
|
|
POST /api/method/building_material.building_material.api.item_feedback.delete
|
|
|
|
Body: {
|
|
"name": "ITEM-PRODUCT_ID-user@email.com"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Review Entity
|
|
|
|
```dart
|
|
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
|
|
```dart
|
|
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
|
|
|
|
```dart
|
|
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`
|