@86d-app/reviews 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +1 -0
- package/AGENTS.md +54 -18
- package/README.md +150 -41
- package/dist/__tests__/controllers.test.d.ts +2 -0
- package/dist/__tests__/controllers.test.d.ts.map +1 -0
- package/dist/__tests__/endpoint-security.test.d.ts +2 -0
- package/dist/__tests__/endpoint-security.test.d.ts.map +1 -0
- package/dist/__tests__/new-features.test.d.ts +2 -0
- package/dist/__tests__/new-features.test.d.ts.map +1 -0
- package/dist/__tests__/service-impl.test.d.ts +2 -0
- package/dist/__tests__/service-impl.test.d.ts.map +1 -0
- package/dist/admin/components/index.d.ts +4 -0
- package/dist/admin/components/index.d.ts.map +1 -0
- package/dist/admin/components/review-analytics.d.ts +2 -0
- package/dist/admin/components/review-analytics.d.ts.map +1 -0
- package/dist/admin/components/review-list.d.ts +2 -0
- package/dist/admin/components/review-list.d.ts.map +1 -0
- package/dist/admin/components/review-moderation.d.ts +6 -0
- package/dist/admin/components/review-moderation.d.ts.map +1 -0
- package/dist/admin/endpoints/approve-review.d.ts +16 -0
- package/dist/admin/endpoints/approve-review.d.ts.map +1 -0
- package/dist/admin/endpoints/delete-review.d.ts +16 -0
- package/dist/admin/endpoints/delete-review.d.ts.map +1 -0
- package/dist/admin/endpoints/get-review.d.ts +16 -0
- package/dist/admin/endpoints/get-review.d.ts.map +1 -0
- package/dist/admin/endpoints/index.d.ts +167 -0
- package/dist/admin/endpoints/index.d.ts.map +1 -0
- package/dist/admin/endpoints/list-reports.d.ts +17 -0
- package/dist/admin/endpoints/list-reports.d.ts.map +1 -0
- package/dist/admin/endpoints/list-review-requests.d.ts +11 -0
- package/dist/admin/endpoints/list-review-requests.d.ts.map +1 -0
- package/dist/admin/endpoints/list-reviews.d.ts +18 -0
- package/dist/admin/endpoints/list-reviews.d.ts.map +1 -0
- package/dist/admin/endpoints/reject-review.d.ts +16 -0
- package/dist/admin/endpoints/reject-review.d.ts.map +1 -0
- package/dist/admin/endpoints/respond-review.d.ts +19 -0
- package/dist/admin/endpoints/respond-review.d.ts.map +1 -0
- package/dist/admin/endpoints/review-analytics.d.ts +6 -0
- package/dist/admin/endpoints/review-analytics.d.ts.map +1 -0
- package/dist/admin/endpoints/review-request-stats.d.ts +6 -0
- package/dist/admin/endpoints/review-request-stats.d.ts.map +1 -0
- package/dist/admin/endpoints/send-review-request.d.ts +23 -0
- package/dist/admin/endpoints/send-review-request.d.ts.map +1 -0
- package/dist/admin/endpoints/update-report.d.ts +22 -0
- package/dist/admin/endpoints/update-report.d.ts.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/schema.d.ts +136 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/service-impl.d.ts +6 -0
- package/dist/service-impl.d.ts.map +1 -0
- package/dist/service.d.ts +149 -0
- package/dist/service.d.ts.map +1 -0
- package/dist/store/components/_hooks.d.ts +6 -0
- package/dist/store/components/_hooks.d.ts.map +1 -0
- package/dist/store/components/_utils.d.ts +3 -0
- package/dist/store/components/_utils.d.ts.map +1 -0
- package/dist/store/components/distribution-bars.d.ts +5 -0
- package/dist/store/components/distribution-bars.d.ts.map +1 -0
- package/dist/store/components/index.d.ts +18 -0
- package/dist/store/components/index.d.ts.map +1 -0
- package/dist/store/components/product-reviews.d.ts +5 -0
- package/dist/store/components/product-reviews.d.ts.map +1 -0
- package/dist/store/components/review-card.d.ts +18 -0
- package/dist/store/components/review-card.d.ts.map +1 -0
- package/dist/store/components/review-form.d.ts +5 -0
- package/dist/store/components/review-form.d.ts.map +1 -0
- package/dist/store/components/reviews-summary.d.ts +4 -0
- package/dist/store/components/reviews-summary.d.ts.map +1 -0
- package/dist/store/components/star-display.d.ts +5 -0
- package/dist/store/components/star-display.d.ts.map +1 -0
- package/dist/store/components/star-picker.d.ts +5 -0
- package/dist/store/components/star-picker.d.ts.map +1 -0
- package/dist/store/endpoints/index.d.ts +116 -0
- package/dist/store/endpoints/index.d.ts.map +1 -0
- package/dist/store/endpoints/list-my-reviews.d.ts +30 -0
- package/dist/store/endpoints/list-my-reviews.d.ts.map +1 -0
- package/dist/store/endpoints/list-product-reviews.d.ts +23 -0
- package/dist/store/endpoints/list-product-reviews.d.ts.map +1 -0
- package/dist/store/endpoints/mark-helpful.d.ts +18 -0
- package/dist/store/endpoints/mark-helpful.d.ts.map +1 -0
- package/dist/store/endpoints/report-review.d.ts +27 -0
- package/dist/store/endpoints/report-review.d.ts.map +1 -0
- package/dist/store/endpoints/submit-review.d.ts +25 -0
- package/dist/store/endpoints/submit-review.d.ts.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/controllers.test.ts +1074 -0
- package/src/__tests__/endpoint-security.test.ts +559 -0
- package/src/__tests__/new-features.test.ts +618 -0
- package/src/__tests__/service-impl.test.ts +1 -1
- package/src/admin/endpoints/index.ts +4 -0
- package/src/admin/endpoints/list-reports.ts +25 -0
- package/src/admin/endpoints/update-report.ts +22 -0
- package/src/index.ts +7 -1
- package/src/schema.ts +28 -0
- package/src/service-impl.ts +151 -3
- package/src/service.ts +61 -0
- package/src/store/endpoints/index.ts +2 -0
- package/src/store/endpoints/list-my-reviews.ts +1 -1
- package/src/store/endpoints/list-product-reviews.ts +6 -2
- package/src/store/endpoints/mark-helpful.ts +20 -1
- package/src/store/endpoints/report-review.ts +38 -0
- package/src/store/endpoints/submit-review.ts +33 -7
- package/COMPONENTS.md +0 -34
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[0m[2m[35m$[0m [2m[1mtsc[0m
|
package/AGENTS.md
CHANGED
|
@@ -1,41 +1,77 @@
|
|
|
1
1
|
# reviews module
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Product reviews, ratings, reporting, and helpfulness voting. Reviews start as `pending` and require admin approval before being publicly visible (unless `autoApprove` is set).
|
|
4
|
+
|
|
5
|
+
## Structure
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
src/
|
|
9
|
+
index.ts Module factory, options, type re-exports
|
|
10
|
+
schema.ts review, reviewVote, reviewReport tables
|
|
11
|
+
service.ts ReviewController interface + types
|
|
12
|
+
service-impl.ts Controller implementation
|
|
13
|
+
store/endpoints/ 5 public endpoints
|
|
14
|
+
store/components/ Customer-facing review UI (TSX + MDX)
|
|
15
|
+
admin/endpoints/ 12 admin endpoints
|
|
16
|
+
admin/components/ Admin review management UI
|
|
17
|
+
__tests__/ 4 test files (246 tests)
|
|
18
|
+
```
|
|
4
19
|
|
|
5
20
|
## Schema
|
|
6
21
|
|
|
7
|
-
- `review` —
|
|
22
|
+
- `review` — rating (1–5), author info, body, images, moderation status, helpfulness count, merchant response
|
|
23
|
+
- `reviewVote` — tracks who voted helpful (reviewId + voterId) for deduplication
|
|
24
|
+
- `reviewReport` — abuse/spam reports (reviewId, reason, status: pending/resolved/dismissed)
|
|
8
25
|
|
|
9
|
-
##
|
|
26
|
+
## Options
|
|
10
27
|
|
|
11
|
-
|
|
28
|
+
| Key | Type | Default | Description |
|
|
29
|
+
|-----|------|---------|-------------|
|
|
30
|
+
| `autoApprove` | `"true" \| "false"` | `"false"` | Skip moderation queue |
|
|
12
31
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
- `
|
|
16
|
-
- `
|
|
17
|
-
- `
|
|
18
|
-
- `
|
|
19
|
-
-
|
|
32
|
+
## Key patterns
|
|
33
|
+
|
|
34
|
+
- **Duplicate prevention**: `hasReviewedProduct(customerId, productId)` — one review per customer per product (enforced in submit endpoint for authenticated users)
|
|
35
|
+
- **Vote deduplication**: `voteHelpful(reviewId, voterId)` — authenticated users can only vote once per review; anonymous users get simple `markHelpful` increment
|
|
36
|
+
- **Sorting**: `listReviewsByProduct` supports `sortBy`: recent, oldest, highest, lowest, helpful
|
|
37
|
+
- **Photo reviews**: `images` field accepts up to 5 `{url, caption?}` objects
|
|
38
|
+
- **Reporting**: customers can report reviews as spam/offensive/fake/irrelevant/harassment/other
|
|
39
|
+
- **Analytics**: `getReviewAnalytics()` includes `reportedCount` (unique reviews with pending reports)
|
|
20
40
|
|
|
21
41
|
## Endpoints
|
|
22
42
|
|
|
23
43
|
### Store
|
|
24
|
-
- `POST /reviews` — submit
|
|
25
|
-
- `GET /reviews/
|
|
44
|
+
- `POST /reviews` — submit review (duplicate check, images, sanitized input)
|
|
45
|
+
- `GET /reviews/me` — list authenticated user's reviews (paginated)
|
|
46
|
+
- `GET /reviews/products/:productId` — approved reviews + summary (sortBy: recent/oldest/highest/lowest/helpful)
|
|
47
|
+
- `POST /reviews/:id/helpful` — vote helpful (deduplicated for auth users)
|
|
48
|
+
- `POST /reviews/:id/report` — report review (reason + optional details)
|
|
26
49
|
|
|
27
50
|
### Admin
|
|
28
51
|
- `GET /admin/reviews` — list all reviews (status/productId filters)
|
|
52
|
+
- `GET /admin/reviews/analytics` — review analytics (includes reportedCount)
|
|
53
|
+
- `GET /admin/reviews/reports` — list reports (status/reviewId filters)
|
|
54
|
+
- `PUT /admin/reviews/reports/:id/update` — resolve/dismiss a report
|
|
55
|
+
- `GET /admin/reviews/requests` — list review request emails
|
|
56
|
+
- `GET /admin/reviews/request-stats` — review request stats
|
|
57
|
+
- `POST /admin/reviews/send-request` — send review request email
|
|
58
|
+
- `GET /admin/reviews/:id` — get single review
|
|
29
59
|
- `PUT /admin/reviews/:id/approve` — approve
|
|
30
60
|
- `PUT /admin/reviews/:id/reject` — reject
|
|
61
|
+
- `POST /admin/reviews/:id/respond` — add merchant response
|
|
31
62
|
- `DELETE /admin/reviews/:id/delete` — delete
|
|
32
63
|
|
|
33
|
-
##
|
|
64
|
+
## Security
|
|
34
65
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
66
|
+
- `customerId` derived from session — never accepted from client
|
|
67
|
+
- `isVerifiedPurchase` always `false` from store endpoint — only admin/system can set
|
|
68
|
+
- Report `reason` is enum-validated (spam, offensive, fake, irrelevant, harassment, other)
|
|
69
|
+
- Image URLs validated as URLs; captions sanitized
|
|
70
|
+
- All text inputs sanitized via `sanitizeText`
|
|
38
71
|
|
|
39
72
|
## Tests
|
|
40
73
|
|
|
41
|
-
|
|
74
|
+
- `service-impl.test.ts` — 109 controller unit tests
|
|
75
|
+
- `controllers.test.ts` — 52 edge case tests
|
|
76
|
+
- `endpoint-security.test.ts` — 45 security regression tests
|
|
77
|
+
- `new-features.test.ts` — 40 tests covering photos, duplicate prevention, vote dedup, sorting, reporting, analytics
|
package/README.md
CHANGED
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
> [!WARNING]
|
|
18
18
|
> This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.
|
|
19
19
|
|
|
20
|
-
#
|
|
20
|
+
# Reviews Module
|
|
21
21
|
|
|
22
|
-
Product reviews and ratings for the 86d commerce platform.
|
|
22
|
+
Product reviews and ratings for the 86d commerce platform. Supports moderation queue, photo reviews, helpfulness voting with deduplication, review sorting, abuse reporting, and merchant responses.
|
|
23
23
|
|
|
24
|
-
 
|
|
25
25
|
|
|
26
26
|
## Installation
|
|
27
27
|
|
|
@@ -62,10 +62,37 @@ When `autoApprove: "true"`, new reviews skip the pending state and go directly t
|
|
|
62
62
|
|
|
63
63
|
| Method | Path | Description |
|
|
64
64
|
|---|---|---|
|
|
65
|
-
| `POST` | `/reviews` | Submit a review (
|
|
66
|
-
| `GET` | `/reviews/
|
|
65
|
+
| `POST` | `/reviews` | Submit a review (with optional images, duplicate prevention) |
|
|
66
|
+
| `GET` | `/reviews/me` | List authenticated user's reviews (paginated) |
|
|
67
|
+
| `GET` | `/reviews/products/:productId` | List approved reviews + rating summary (sortable) |
|
|
68
|
+
| `POST` | `/reviews/:id/helpful` | Vote review as helpful (deduplicated for auth users) |
|
|
69
|
+
| `POST` | `/reviews/:id/report` | Report a review for abuse/spam |
|
|
70
|
+
|
|
71
|
+
### Submit Review (`POST /reviews`)
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"productId": "prod_abc",
|
|
76
|
+
"authorName": "Jane Doe",
|
|
77
|
+
"authorEmail": "jane@example.com",
|
|
78
|
+
"rating": 5,
|
|
79
|
+
"title": "Excellent product!",
|
|
80
|
+
"body": "Exactly what I needed.",
|
|
81
|
+
"images": [
|
|
82
|
+
{ "url": "https://example.com/photo.jpg", "caption": "Front view" }
|
|
83
|
+
]
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Returns `409` if the authenticated customer has already reviewed this product.
|
|
88
|
+
|
|
89
|
+
### List Product Reviews (`GET /reviews/products/:productId`)
|
|
90
|
+
|
|
91
|
+
Query parameters:
|
|
92
|
+
- `take` (1–100, default 20) — page size
|
|
93
|
+
- `skip` (default 0) — offset
|
|
94
|
+
- `sortBy` — `recent` | `oldest` | `highest` | `lowest` | `helpful` (default: `recent`)
|
|
67
95
|
|
|
68
|
-
**Response for `GET /reviews/products/:productId`:**
|
|
69
96
|
```json
|
|
70
97
|
{
|
|
71
98
|
"reviews": [...],
|
|
@@ -77,13 +104,32 @@ When `autoApprove: "true"`, new reviews skip the pending state and go directly t
|
|
|
77
104
|
}
|
|
78
105
|
```
|
|
79
106
|
|
|
107
|
+
### Report Review (`POST /reviews/:id/report`)
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"reason": "spam",
|
|
112
|
+
"details": "This review is advertising another product"
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
Reason must be one of: `spam`, `offensive`, `fake`, `irrelevant`, `harassment`, `other`.
|
|
117
|
+
|
|
80
118
|
## Admin Endpoints
|
|
81
119
|
|
|
82
120
|
| Method | Path | Description |
|
|
83
121
|
|---|---|---|
|
|
84
122
|
| `GET` | `/admin/reviews` | List all reviews (filter: `status`, `productId`) |
|
|
123
|
+
| `GET` | `/admin/reviews/analytics` | Review analytics (includes report counts) |
|
|
124
|
+
| `GET` | `/admin/reviews/reports` | List abuse reports (filter: `status`, `reviewId`) |
|
|
125
|
+
| `PUT` | `/admin/reviews/reports/:id/update` | Resolve or dismiss a report |
|
|
126
|
+
| `GET` | `/admin/reviews/requests` | List review request emails |
|
|
127
|
+
| `GET` | `/admin/reviews/request-stats` | Review request statistics |
|
|
128
|
+
| `POST` | `/admin/reviews/send-request` | Send a review request email |
|
|
129
|
+
| `GET` | `/admin/reviews/:id` | Get a single review |
|
|
85
130
|
| `PUT` | `/admin/reviews/:id/approve` | Approve a review |
|
|
86
131
|
| `PUT` | `/admin/reviews/:id/reject` | Reject a review |
|
|
132
|
+
| `POST` | `/admin/reviews/:id/respond` | Add merchant response |
|
|
87
133
|
| `DELETE` | `/admin/reviews/:id/delete` | Delete a review permanently |
|
|
88
134
|
|
|
89
135
|
## Controller API
|
|
@@ -98,15 +144,16 @@ controller.createReview(params: {
|
|
|
98
144
|
body: string;
|
|
99
145
|
customerId?: string;
|
|
100
146
|
isVerifiedPurchase?: boolean;
|
|
147
|
+
images?: Array<{ url: string; caption?: string }>;
|
|
101
148
|
}): Promise<Review>
|
|
102
149
|
|
|
103
150
|
controller.getReview(id: string): Promise<Review | null>
|
|
104
151
|
|
|
105
|
-
// Returns only approved reviews by default (set approvedOnly: false for all)
|
|
106
152
|
controller.listReviewsByProduct(productId: string, params?: {
|
|
107
153
|
approvedOnly?: boolean;
|
|
108
154
|
take?: number;
|
|
109
155
|
skip?: number;
|
|
156
|
+
sortBy?: "recent" | "oldest" | "highest" | "lowest" | "helpful";
|
|
110
157
|
}): Promise<Review[]>
|
|
111
158
|
|
|
112
159
|
controller.listReviews(params?: {
|
|
@@ -120,52 +167,47 @@ controller.updateReviewStatus(id: string, status: ReviewStatus): Promise<Review
|
|
|
120
167
|
|
|
121
168
|
controller.deleteReview(id: string): Promise<boolean>
|
|
122
169
|
|
|
123
|
-
// Calculates stats from approved reviews only
|
|
124
170
|
controller.getProductRatingSummary(productId: string): Promise<RatingSummary>
|
|
125
|
-
```
|
|
126
171
|
|
|
127
|
-
|
|
172
|
+
controller.hasReviewedProduct(customerId: string, productId: string): Promise<boolean>
|
|
128
173
|
|
|
129
|
-
|
|
174
|
+
controller.voteHelpful(reviewId: string, voterId: string): Promise<{
|
|
175
|
+
review: Review;
|
|
176
|
+
alreadyVoted: boolean;
|
|
177
|
+
} | null>
|
|
130
178
|
|
|
131
|
-
|
|
132
|
-
interface RatingSummary {
|
|
133
|
-
average: number; // e.g. 4.3
|
|
134
|
-
count: number; // number of approved reviews
|
|
135
|
-
distribution: Record<string, number>; // { "1": 0, "2": 1, "3": 2, "4": 4, "5": 5 }
|
|
136
|
-
}
|
|
137
|
-
```
|
|
179
|
+
controller.markHelpful(id: string): Promise<Review | null>
|
|
138
180
|
|
|
139
|
-
|
|
181
|
+
controller.reportReview(params: {
|
|
182
|
+
reviewId: string;
|
|
183
|
+
reporterId?: string;
|
|
184
|
+
reason: string;
|
|
185
|
+
details?: string;
|
|
186
|
+
}): Promise<ReviewReport>
|
|
140
187
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
152
|
-
// review.status === "pending"
|
|
153
|
-
|
|
154
|
-
// Admin approves it
|
|
155
|
-
await controller.updateReviewStatus(review.id, "approved");
|
|
156
|
-
|
|
157
|
-
// Fetch public ratings for a product page
|
|
158
|
-
const summary = await controller.getProductRatingSummary("prod_abc");
|
|
159
|
-
// { average: 5.0, count: 1, distribution: { "5": 1, "4": 0, ... } }
|
|
160
|
-
|
|
161
|
-
// Fetch approved reviews for display
|
|
162
|
-
const reviews = await controller.listReviewsByProduct("prod_abc");
|
|
188
|
+
controller.listReports(params?: {
|
|
189
|
+
status?: ReportStatus;
|
|
190
|
+
reviewId?: string;
|
|
191
|
+
take?: number;
|
|
192
|
+
skip?: number;
|
|
193
|
+
}): Promise<ReviewReport[]>
|
|
194
|
+
|
|
195
|
+
controller.updateReportStatus(id: string, status: ReportStatus): Promise<ReviewReport | null>
|
|
196
|
+
|
|
197
|
+
controller.getReportCount(reviewId: string): Promise<number>
|
|
163
198
|
```
|
|
164
199
|
|
|
165
200
|
## Types
|
|
166
201
|
|
|
167
202
|
```ts
|
|
168
203
|
type ReviewStatus = "pending" | "approved" | "rejected";
|
|
204
|
+
type ReportStatus = "pending" | "resolved" | "dismissed";
|
|
205
|
+
type ReviewSortBy = "recent" | "oldest" | "highest" | "lowest" | "helpful";
|
|
206
|
+
|
|
207
|
+
interface ReviewImage {
|
|
208
|
+
url: string;
|
|
209
|
+
caption?: string;
|
|
210
|
+
}
|
|
169
211
|
|
|
170
212
|
interface Review {
|
|
171
213
|
id: string;
|
|
@@ -179,13 +221,80 @@ interface Review {
|
|
|
179
221
|
status: ReviewStatus;
|
|
180
222
|
isVerifiedPurchase: boolean;
|
|
181
223
|
helpfulCount: number;
|
|
224
|
+
images?: ReviewImage[];
|
|
225
|
+
merchantResponse?: string;
|
|
226
|
+
merchantResponseAt?: Date;
|
|
227
|
+
moderationNote?: string;
|
|
182
228
|
createdAt: Date;
|
|
183
229
|
updatedAt: Date;
|
|
184
230
|
}
|
|
185
231
|
|
|
232
|
+
interface ReviewVote {
|
|
233
|
+
id: string;
|
|
234
|
+
reviewId: string;
|
|
235
|
+
voterId: string;
|
|
236
|
+
createdAt: Date;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
interface ReviewReport {
|
|
240
|
+
id: string;
|
|
241
|
+
reviewId: string;
|
|
242
|
+
reporterId?: string;
|
|
243
|
+
reason: string;
|
|
244
|
+
details?: string;
|
|
245
|
+
status: ReportStatus;
|
|
246
|
+
createdAt: Date;
|
|
247
|
+
}
|
|
248
|
+
|
|
186
249
|
interface RatingSummary {
|
|
187
250
|
average: number;
|
|
188
251
|
count: number;
|
|
189
252
|
distribution: Record<string, number>;
|
|
190
253
|
}
|
|
254
|
+
|
|
255
|
+
interface ReviewAnalytics {
|
|
256
|
+
totalReviews: number;
|
|
257
|
+
pendingCount: number;
|
|
258
|
+
approvedCount: number;
|
|
259
|
+
rejectedCount: number;
|
|
260
|
+
averageRating: number;
|
|
261
|
+
ratingsDistribution: Record<string, number>;
|
|
262
|
+
withMerchantResponse: number;
|
|
263
|
+
reportedCount: number;
|
|
264
|
+
}
|
|
191
265
|
```
|
|
266
|
+
|
|
267
|
+
## Store Components
|
|
268
|
+
|
|
269
|
+
### ReviewsSummary
|
|
270
|
+
|
|
271
|
+
Compact star rating and count for product cards.
|
|
272
|
+
|
|
273
|
+
| Prop | Type | Description |
|
|
274
|
+
|------|------|-------------|
|
|
275
|
+
| `productId` | `string` | Product ID to fetch review summary for |
|
|
276
|
+
|
|
277
|
+
```mdx
|
|
278
|
+
<ReviewsSummary productId={product.id} />
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### ProductReviews
|
|
282
|
+
|
|
283
|
+
Full reviews section with summary, distribution bars, review list, and submit form.
|
|
284
|
+
|
|
285
|
+
| Prop | Type | Default | Description |
|
|
286
|
+
|------|------|---------|-------------|
|
|
287
|
+
| `productId` | `string` | — | Product ID |
|
|
288
|
+
| `title` | `string` | `"Customer Reviews"` | Section heading |
|
|
289
|
+
|
|
290
|
+
```mdx
|
|
291
|
+
<ProductReviews productId={product.id} />
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
## Notes
|
|
295
|
+
|
|
296
|
+
- Only approved reviews appear in product listings and rating summaries
|
|
297
|
+
- Authenticated customers can only submit one review per product
|
|
298
|
+
- Helpfulness votes are deduplicated for authenticated users (anonymous votes are not tracked)
|
|
299
|
+
- Report reasons are enum-validated; details are sanitized
|
|
300
|
+
- Images are validated as URLs with a max of 5 per review
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controllers.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/controllers.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endpoint-security.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/endpoint-security.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"new-features.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/new-features.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-impl.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/service-impl.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/admin/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-analytics.d.ts","sourceRoot":"","sources":["../../../src/admin/components/review-analytics.tsx"],"names":[],"mappings":"AA8FA,wBAAgB,eAAe,gCA8H9B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-list.d.ts","sourceRoot":"","sources":["../../../src/admin/components/review-list.tsx"],"names":[],"mappings":"AAqGA,wBAAgB,UAAU,gCA8MzB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-moderation.d.ts","sourceRoot":"","sources":["../../../src/admin/components/review-moderation.tsx"],"names":[],"mappings":"AA8FA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACtB,+BA4VA"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "@86d-app/core";
|
|
2
|
+
export declare const approveReview: import("better-call").StrictEndpoint<"/admin/reviews/:id/approve", {
|
|
3
|
+
method: "PUT";
|
|
4
|
+
params: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
error: string;
|
|
9
|
+
status: number;
|
|
10
|
+
review?: never;
|
|
11
|
+
} | {
|
|
12
|
+
review: import("../..").Review;
|
|
13
|
+
error?: never;
|
|
14
|
+
status?: never;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=approve-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve-review.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/approve-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,CAAC,EAAE,MAAM,eAAe,CAAC;AAGvD,eAAO,MAAM,aAAa;;;;;;;;;;;;;EAezB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "@86d-app/core";
|
|
2
|
+
export declare const deleteReview: import("better-call").StrictEndpoint<"/admin/reviews/:id/delete", {
|
|
3
|
+
method: "DELETE";
|
|
4
|
+
params: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
error: string;
|
|
9
|
+
status: number;
|
|
10
|
+
deleted?: never;
|
|
11
|
+
} | {
|
|
12
|
+
deleted: boolean;
|
|
13
|
+
error?: never;
|
|
14
|
+
status?: never;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=delete-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"delete-review.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/delete-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,CAAC,EAAE,MAAM,eAAe,CAAC;AAGvD,eAAO,MAAM,YAAY;;;;;;;;;;;;;EAaxB,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { z } from "@86d-app/core";
|
|
2
|
+
export declare const getReview: import("better-call").StrictEndpoint<"/admin/reviews/:id", {
|
|
3
|
+
method: "GET";
|
|
4
|
+
params: z.ZodObject<{
|
|
5
|
+
id: z.ZodString;
|
|
6
|
+
}, z.core.$strip>;
|
|
7
|
+
}, {
|
|
8
|
+
error: string;
|
|
9
|
+
status: number;
|
|
10
|
+
review?: never;
|
|
11
|
+
} | {
|
|
12
|
+
review: import("../..").Review;
|
|
13
|
+
error?: never;
|
|
14
|
+
status?: never;
|
|
15
|
+
}>;
|
|
16
|
+
//# sourceMappingURL=get-review.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-review.d.ts","sourceRoot":"","sources":["../../../src/admin/endpoints/get-review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAuB,CAAC,EAAE,MAAM,eAAe,CAAC;AAGvD,eAAO,MAAM,SAAS;;;;;;;;;;;;;EAYrB,CAAC"}
|