Skip to content

Display Rating and Reviews on Home Page #1

Description

@gerardogreco-blx

📋 Context

File involved: src/ClaudeClothes.Web/Pages/Index.razor


🎯 User Story

As a visitor to the ClaudeClothes platform
I want to view the average rating and number of reviews for each clothing item directly on the home page
So that I can quickly assess the quality and popularity of products before clicking to see details


✅ Acceptance Criteria

1. Average Rating Display

  • The average rating must be displayed for each clothing item card in the home page grid
  • The rating must be shown using visual stars (Bootstrap Icons: bi-star-fill, bi-star-half, bi-star)
  • The stars must accurately reflect the AverageRating value:
    • Full star for values >= 1
    • Half star for decimal values (e.g., 4.5)
    • Empty star for remaining values up to 5 total stars
  • The numeric rating value must be displayed next to the stars in "X.X" format (e.g., "4.5")
  • If AverageRating is 0 or there are no reviews, the message "No reviews" must be displayed

2. Review Count Display

  • The total number of reviews must be displayed in parentheses after the numeric rating
  • The count must derive from the Reviews.Count property of the ClothingItem model
  • Example output: "4.5 (8)" means rating 4.5 with 8 reviews

3. Layout and Positioning

  • The rating section must be positioned in the card footer (card-footer-section)
  • It must be aligned to the left in the footer, with the "View Details" button aligned to the right
  • The rating must be contained in a badge with the class rating-badge

4. Design and Visual Style

The design follows the project's bold and colorful "neobrutalism" theme:

  • Stars: yellow color (#FFD23F) with black drop-shadow for bold effect
  • Numeric value: Bebas Neue font, weight 900, size 1.3rem, black color (#1A1A1A)
  • Review count: black color, size 0.9rem, weight 600
  • "No reviews" badge: light gray text (#a0aec0), empty star icon

🔧 Technical Implementation Details

Models Involved

ClothingItem.cs (src/ClaudeClothes.Core/Models/)

public class ClothingItem
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public string Description { get; set; }
    public decimal Price { get; set; }
    public string Size { get; set; }
    public double AverageRating { get; set; }  // ← Used to display the rating
    public ICollection<Review> Reviews { get; set; }  // ← Used to count reviews
}

Razor Logic to Implement

Location: Inside the @foreach (var clothingItem in pagedClothingItems.Items) loop in the card-footer-section section

Razor Code:

<div class="card-footer-section">
    <div class="rating-badge">
        @if (clothingItem.AverageRating > 0)
        {
            <div class="rating-stars"
                 role="img"
                 aria-label="Rating: @clothingItem.AverageRating.ToString("F1") stars out of 5">
                @for (int i = 1; i <= 5; i++)
                {
                    if (i <= Math.Floor(clothingItem.AverageRating))
                    {
                        <i class="bi bi-star-fill" aria-hidden="true"></i>
                    }
                    else if (i - clothingItem.AverageRating < 1)
                    {
                        <i class="bi bi-star-half" aria-hidden="true"></i>
                    }
                    else
                    {
                        <i class="bi bi-star" aria-hidden="true"></i>
                    }
                }
            </div>
            <span class="rating-value">@clothingItem.AverageRating.ToString("F1")</span>
            <span class="review-count">(@clothingItem.Reviews.Count)</span>
        }
        else
        {
            <span class="no-rating">
                <i class="bi bi-star" aria-hidden="true"></i> No reviews
            </span>
        }
    </div>

    <a href="/item/@clothingItem.Id"
       class="btn-view-details"
       aria-label="View details of @clothingItem.Name">
        View Details
        <i class="bi bi-arrow-right" aria-hidden="true"></i>
    </a>
</div>

CSS to Implement

Location: Inside the <style> tag of Index.razor

.card-footer-section {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding-top: 1.5rem;
    border-top: 3px dashed #1A1A1A;
}

.rating-badge {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}

.rating-stars {
    display: flex;
    gap: 3px;
    color: #FFD23F;
    font-size: 1.1rem;
    filter: drop-shadow(1px 1px 0 #1A1A1A);
}

.rating-value {
    font-weight: 900;
    color: #1A1A1A;
    font-size: 1.3rem;
    font-family: 'Bebas Neue', sans-serif;
}

.review-count {
    color: #1A1A1A;
    font-size: 0.9rem;
    font-weight: 600;
}

.no-rating {
    color: #a0aec0;
    font-size: 0.95rem;
    font-weight: 500;
}

🎨 Visual Behavior

Example 1: Item with Reviews (Rating 4.5, 8 reviews)

Card Footer:
┌─────────────────────────────────────────────────┐
│ ★★★★½  4.5 (8)          [View Details →]       │
└─────────────────────────────────────────────────┘

Example 2: Item without Reviews

Card Footer:
┌─────────────────────────────────────────────────┐
│ ☆ No reviews            [View Details →]       │
└─────────────────────────────────────────────────┘

Example 3: Item with Perfect Rating (5.0, 12 reviews)

Card Footer:
┌─────────────────────────────────────────────────┐
│ ★★★★★  5.0 (12)         [View Details →]       │
└─────────────────────────────────────────────────┘

♿ Accessibility

  • The stars section includes role="img" and descriptive aria-label
  • Decorative icons have aria-hidden="true"
  • Color contrast meets WCAG 2.1 AA standards

🧪 Suggested Tests

Unit Tests

  • Verify that the rating is calculated correctly by the service
  • Verify that Reviews.Count is accurate

E2E Tests

  • Verify that stars are displayed correctly for different rating values (1.0, 2.5, 3.7, 4.0, 5.0)
  • Verify that "No reviews" appears when AverageRating is 0
  • Verify that the review count is accurate
  • Verify responsive layout on mobile and desktop

📚 References

  • Main file: src/ClaudeClothes.Web/Pages/Index.razor
  • Models: src/ClaudeClothes.Core/Models/ClothingItem.cs, Review.cs
  • Bootstrap Icons: https://icons.getbootstrap.com/
  • Font used: Bebas Neue (Google Fonts)

💡 Implementation Notes

  1. Eager Loading: Ensure that the service loads the Reviews collection when retrieving ClothingItem objects for the home page (use .Include(c => c.Reviews) in Entity Framework)

  2. Performance: The review count uses Reviews.Count which is efficient if the collection is already loaded

  3. Half Star Logic:

    • The condition i - clothingItem.AverageRating < 1 determines whether to show a half star
    • Example: if rating is 4.5 and i=5, then 5 - 4.5 = 0.5 < 1, so show half star
  4. Numeric Formatting:

    • ToString("F1") formats the double with 1 decimal place (e.g., 4.5, 3.0, 5.0)
  5. Stylistic Consistency:

    • The style follows the project's "neobrutalism" theme with thick borders, black shadows, and vibrant colors

🎯 Definition of Done

  • Razor code has been implemented in the correct section of Index.razor
  • CSS styles have been added to the <style> tag of Index.razor
  • The service correctly loads the Reviews collection (eager loading)
  • Stars are displayed correctly for all rating values
  • Review count is accurate
  • Layout is responsive on mobile and desktop
  • Accessibility attributes are present
  • Design follows the project's neobrutalism theme
  • E2E tests verify all scenarios

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions