update review api.
This commit is contained in:
265
REVIEWS_QUICK_REFERENCE.md
Normal file
265
REVIEWS_QUICK_REFERENCE.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# 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: () => CircularProgressIndicator(),
|
||||
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`
|
||||
Reference in New Issue
Block a user