Documentation Index Fetch the complete documentation index at: https://mintlify.com/Antony-Figueroa/my-evershop-app/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The Product Reviews extension adds a complete customer review system to your EverShop store. Customers can rate products with stars, write detailed reviews, and see reviews from other customers.
Features
5-star rating system
Review submission form
Average rating calculation
Responsive design
Benefits
Build customer trust
Increase conversions
Gather product feedback
Social proof
Product Reviews Component
The main component is located at extensions/productReviews/src/pages/frontStore/productView/ProductReviews.tsx:
import React , { useState } from 'react' ;
interface Review {
id : string ;
author : string ;
rating : number ;
comment : string ;
createdAt : string ;
}
type ProductReviewsProps = {
product : {
productId : string ;
name : string ;
};
reviews ?: Review [];
action ?: string ;
};
function StarRating ({ rating , interactive = false , onChange } : {
rating : number ;
interactive ?: boolean ;
onChange ?: ( rating : number ) => void
}) {
return (
< div className = "flex gap-1" >
{ [ 1 , 2 , 3 , 4 , 5 ]. map (( star ) => (
< button
key = { star }
type = "button"
disabled = { ! interactive }
onClick = { () => interactive && onChange ?.( star ) }
className = { `text-2xl ${ interactive ? 'cursor-pointer' : 'cursor-default' } ${
star <= rating ? 'text-yellow-400' : 'text-gray-300'
} ` }
>
β
</ button >
)) }
</ div >
);
}
export default function ProductReviews ({ product , reviews = [], action } : ProductReviewsProps ) {
const [ showForm , setShowForm ] = useState ( false );
const [ newReview , setNewReview ] = useState ({
author: '' ,
rating: 5 ,
comment: ''
});
const averageRating = reviews . length > 0
? reviews . reduce (( sum , r ) => sum + r . rating , 0 ) / reviews . length
: 0 ;
const handleSubmit = async ( e : React . FormEvent ) => {
e . preventDefault ();
// Here you would normally submit to an API
console . log ( 'Submitting review:' , newReview );
setShowForm ( false );
setNewReview ({ author: '' , rating: 5 , comment: '' });
};
return (
< div className = "bg-[#F8FAF9] border border-[#E8F5E9] rounded-lg p-6 mt-6" >
< div className = "flex items-center justify-between mb-6" >
< h3 className = "text-xl font-bold text-[#2D5A3D]" >
ReseΓ±as de Clientes
</ h3 >
< button
onClick = { () => setShowForm ( ! showForm ) }
className = "bg-[#2D5A3D] text-white px-4 py-2 rounded-lg hover:bg-[#1E3D2A] transition-colors text-sm"
>
{ showForm ? 'Cancelar' : 'Escribir ReseΓ±a' }
</ button >
</ div >
{ reviews . length > 0 && (
< div className = "mb-6" >
< div className = "flex items-center gap-4 mb-4" >
< StarRating rating = { Math . round ( averageRating ) } />
< span className = "text-[#4A5568]" >
{ averageRating . toFixed ( 1 ) } de 5 ( { reviews . length } reseΓ±as)
</ span >
</ div >
</ div >
) }
{ showForm && (
< form onSubmit = { handleSubmit } className = "bg-white border border-[#E8F5E9] rounded-lg p-4 mb-6" >
< h4 className = "font-semibold text-[#2D5A3D] mb-4" > Nueva ReseΓ±a </ h4 >
< div className = "mb-4" >
< label className = "block text-sm font-medium text-[#4A5568] mb-2" >
Tu Nombre
</ label >
< input
type = "text"
value = { newReview . author }
onChange = { ( e ) => setNewReview ({ ... newReview , author: e . target . value }) }
required
className = "w-full px-4 py-2 border border-[#E8F5E9] rounded-lg focus:outline-none focus:border-[#2D5A3D]"
/>
</ div >
< div className = "mb-4" >
< label className = "block text-sm font-medium text-[#4A5568] mb-2" >
CalificaciΓ³n
</ label >
< StarRating
rating = { newReview . rating }
interactive
onChange = { ( rating ) => setNewReview ({ ... newReview , rating }) }
/>
</ div >
< div className = "mb-4" >
< label className = "block text-sm font-medium text-[#4A5568] mb-2" >
Tu ReseΓ±a
</ label >
< textarea
value = { newReview . comment }
onChange = { ( e ) => setNewReview ({ ... newReview , comment: e . target . value }) }
required
rows = { 4 }
className = "w-full px-4 py-2 border border-[#E8F5E9] rounded-lg focus:outline-none focus:border-[#2D5A3D]"
placeholder = "Comparte tu experiencia con este producto..."
/>
</ div >
< button
type = "submit"
className = "bg-[#2D5A3D] text-white px-6 py-2 rounded-lg hover:bg-[#1E3D2A] transition-colors"
>
Enviar ReseΓ±a
</ button >
</ form >
) }
{ reviews . length === 0 ? (
< p className = "text-[#4A5568] text-center py-4" >
SΓ© el primero en reseΓ±ar este producto.
</ p >
) : (
< div className = "space-y-4" >
{ reviews . map (( review ) => (
< div key = { review . id } className = "border-b border-[#E8F5E9] pb-4 last:border-0" >
< div className = "flex items-center gap-2 mb-2" >
< StarRating rating = { review . rating } />
< span className = "font-medium text-[#2D5A3D]" > { review . author } </ span >
</ div >
< p className = "text-[#4A5568] text-sm" > { review . comment } </ p >
< p className = "text-[#4A5568] text-xs mt-2" >
{new Date ( review . createdAt ). toLocaleDateString ( 'es-ES' ) }
</ p >
</ div >
)) }
</ div >
) }
</ div >
);
}
export const layout = {
areaId: 'productPageBottom' ,
sortOrder: 10
};
export const query = `
query Query {
product(id: getContextValue("productId")) {
productId
name
reviews {
id
author
rating
comment
createdAt
}
}
action: url(routeId: "productReviews")
}
` ;
Component Features
Star Rating Component
The StarRating component can be used in two modes:
Display Mode
Interactive Mode
< StarRating rating = { 4 } />
Shows stars as read-only display < StarRating
rating = { rating }
interactive
onChange = { ( newRating ) => setRating ( newRating ) }
/>
Allows users to click stars to select a rating
Average Rating Calculation
Automatically calculates and displays the average rating:
const averageRating = reviews . length > 0
? reviews . reduce (( sum , r ) => sum + r . rating , 0 ) / reviews . length
: 0 ;
Displayed as: 4.5 de 5 (12 reseΓ±as)
Collapsible form with three fields:
Customer Name
Required text input for reviewerβs name
Star Rating
Interactive star selector (1-5 stars)
Review Text
Multi-line textarea for detailed feedback
Review Display
Each review shows:
β Star rating visualization
π€ Author name
π¬ Review comment
π
Submission date (formatted in Spanish)
Data Structure
interface Review {
id : string ; // Unique review identifier
author : string ; // Customer name
rating : number ; // 1-5 star rating
comment : string ; // Review text
createdAt : string ; // ISO date string
}
GraphQL Integration
The component uses GraphQL to fetch product reviews:
query Query {
product ( id : getContextValue ( "productId" )) {
productId
name
reviews {
id
author
rating
comment
createdAt
}
}
action : url ( routeId : "productReviews" )
}
The action field provides the URL for submitting new reviews via POST request.
Layout Configuration
The component is placed at the bottom of product pages:
export const layout = {
areaId: 'productPageBottom' ,
sortOrder: 10
};
This ensures reviews appear after product details and supplement information.
User Interface
Empty State
When no reviews exist:
βββββββββββββββββββββββββββββββββββββββ
β ReseΓ±as de Clientes [Escribir...] β
βββββββββββββββββββββββββββββββββββββββ€
β β
β SΓ© el primero en reseΓ±ar este β
β producto. β
β β
βββββββββββββββββββββββββββββββββββββββ
With Reviews
βββββββββββββββββββββββββββββββββββββββ
β ReseΓ±as de Clientes [Escribir...] β
βββββββββββββββββββββββββββββββββββββββ€
β β
β
β
β
β
4.5 de 5 (12 reseΓ±as) β
βββββββββββββββββββββββββββββββββββββββ€
β β
β
β
β
β
Juan PΓ©rez β
β Excelente producto, muy efectivo β
β 15 ene 2026 β
βββββββββββββββββββββββββββββββββββββββ€
β β
β
β
β
β MarΓa GarcΓa β
β Buen suplemento, resultados visiblesβ
β 10 ene 2026 β
βββββββββββββββββββββββββββββββββββββββ
Styling
Uses Anaβs Suplements brand colors:
Element Color Purpose Container #F8FAF9Main background Border #E8F5E9Card borders Heading #2D5A3DSection title Button #2D5A3DPrimary actions Button Hover #1E3D2AHover state Text #4A5568Body text Stars (filled) #FCD34DYellow rating stars Stars (empty) #D1D5DBGray empty stars
Extension Structure
extensions/productReviews/
βββ src/
β βββ pages/
β βββ frontStore/
β βββ productView/
β βββ ProductReviews.tsx
βββ package.json
βββ tsconfig.json
Configuration
Enabled in config/default.json:
{
"system" : {
"extensions" : [
{
"name" : "productReviews" ,
"resolve" : "extensions/productReviews" ,
"enabled" : true
}
]
}
}
State Management
The component uses React hooks for state management:
const [ showForm , setShowForm ] = useState ( false ); // Form visibility
const [ newReview , setNewReview ] = useState ({ // Form data
author: '' ,
rating: 5 ,
comment: ''
});
User clicks 'Escribir ReseΓ±a'
Form appears with default 5-star rating
User fills in name, adjusts rating, writes comment
State updates with each field change
User clicks 'Enviar ReseΓ±a'
Form submission handler processes the review
Form resets
Form hides and clears all fields
Best Practices
Moderation : Consider adding admin review moderation before publishing reviews publicly.
Verification : Implement purchase verification to ensure only real customers can review products.
Incentives : Consider offering loyalty points or discounts for leaving reviews to increase participation.
Internationalization
All text is currently in Spanish:
βReseΓ±as de Clientesβ (Customer Reviews)
βEscribir ReseΓ±aβ (Write Review)
βNueva ReseΓ±aβ (New Review)
βTu Nombreβ (Your Name)
βCalificaciΓ³nβ (Rating)
βTu ReseΓ±aβ (Your Review)
βSΓ© el primero en reseΓ±ar este productoβ (Be the first to review)
To support other languages, extract strings to translation files.
Next Steps
Offline Payments Learn about payment methods
Page Components Create custom product page components