@86d-app/reviews 0.0.3 → 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 +151 -43
- 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
|
@@ -9,20 +9,19 @@
|
|
|
9
9
|
</p>
|
|
10
10
|
|
|
11
11
|
<p align="center">
|
|
12
|
-
<a href="https://vercel.com/changelog"><strong>npm</strong></a> ·
|
|
13
12
|
<a href="https://x.com/86d_app"><strong>X</strong></a> ·
|
|
14
|
-
<a href="https://
|
|
13
|
+
<a href="https://www.linkedin.com/company/86d"><strong>LinkedIn</strong></a>
|
|
15
14
|
</p>
|
|
16
15
|
<br/>
|
|
17
16
|
|
|
18
17
|
> [!WARNING]
|
|
19
18
|
> This project is under active development and is not ready for production use. Please proceed with caution. Use at your own risk.
|
|
20
19
|
|
|
21
|
-
#
|
|
20
|
+
# Reviews Module
|
|
22
21
|
|
|
23
|
-
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.
|
|
24
23
|
|
|
25
|
-
 
|
|
26
25
|
|
|
27
26
|
## Installation
|
|
28
27
|
|
|
@@ -63,10 +62,37 @@ When `autoApprove: "true"`, new reviews skip the pending state and go directly t
|
|
|
63
62
|
|
|
64
63
|
| Method | Path | Description |
|
|
65
64
|
|---|---|---|
|
|
66
|
-
| `POST` | `/reviews` | Submit a review (
|
|
67
|
-
| `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`)
|
|
68
95
|
|
|
69
|
-
**Response for `GET /reviews/products/:productId`:**
|
|
70
96
|
```json
|
|
71
97
|
{
|
|
72
98
|
"reviews": [...],
|
|
@@ -78,13 +104,32 @@ When `autoApprove: "true"`, new reviews skip the pending state and go directly t
|
|
|
78
104
|
}
|
|
79
105
|
```
|
|
80
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
|
+
|
|
81
118
|
## Admin Endpoints
|
|
82
119
|
|
|
83
120
|
| Method | Path | Description |
|
|
84
121
|
|---|---|---|
|
|
85
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 |
|
|
86
130
|
| `PUT` | `/admin/reviews/:id/approve` | Approve a review |
|
|
87
131
|
| `PUT` | `/admin/reviews/:id/reject` | Reject a review |
|
|
132
|
+
| `POST` | `/admin/reviews/:id/respond` | Add merchant response |
|
|
88
133
|
| `DELETE` | `/admin/reviews/:id/delete` | Delete a review permanently |
|
|
89
134
|
|
|
90
135
|
## Controller API
|
|
@@ -99,15 +144,16 @@ controller.createReview(params: {
|
|
|
99
144
|
body: string;
|
|
100
145
|
customerId?: string;
|
|
101
146
|
isVerifiedPurchase?: boolean;
|
|
147
|
+
images?: Array<{ url: string; caption?: string }>;
|
|
102
148
|
}): Promise<Review>
|
|
103
149
|
|
|
104
150
|
controller.getReview(id: string): Promise<Review | null>
|
|
105
151
|
|
|
106
|
-
// Returns only approved reviews by default (set approvedOnly: false for all)
|
|
107
152
|
controller.listReviewsByProduct(productId: string, params?: {
|
|
108
153
|
approvedOnly?: boolean;
|
|
109
154
|
take?: number;
|
|
110
155
|
skip?: number;
|
|
156
|
+
sortBy?: "recent" | "oldest" | "highest" | "lowest" | "helpful";
|
|
111
157
|
}): Promise<Review[]>
|
|
112
158
|
|
|
113
159
|
controller.listReviews(params?: {
|
|
@@ -121,52 +167,47 @@ controller.updateReviewStatus(id: string, status: ReviewStatus): Promise<Review
|
|
|
121
167
|
|
|
122
168
|
controller.deleteReview(id: string): Promise<boolean>
|
|
123
169
|
|
|
124
|
-
// Calculates stats from approved reviews only
|
|
125
170
|
controller.getProductRatingSummary(productId: string): Promise<RatingSummary>
|
|
126
|
-
```
|
|
127
171
|
|
|
128
|
-
|
|
172
|
+
controller.hasReviewedProduct(customerId: string, productId: string): Promise<boolean>
|
|
129
173
|
|
|
130
|
-
|
|
174
|
+
controller.voteHelpful(reviewId: string, voterId: string): Promise<{
|
|
175
|
+
review: Review;
|
|
176
|
+
alreadyVoted: boolean;
|
|
177
|
+
} | null>
|
|
131
178
|
|
|
132
|
-
|
|
133
|
-
interface RatingSummary {
|
|
134
|
-
average: number; // e.g. 4.3
|
|
135
|
-
count: number; // number of approved reviews
|
|
136
|
-
distribution: Record<string, number>; // { "1": 0, "2": 1, "3": 2, "4": 4, "5": 5 }
|
|
137
|
-
}
|
|
138
|
-
```
|
|
179
|
+
controller.markHelpful(id: string): Promise<Review | null>
|
|
139
180
|
|
|
140
|
-
|
|
181
|
+
controller.reportReview(params: {
|
|
182
|
+
reviewId: string;
|
|
183
|
+
reporterId?: string;
|
|
184
|
+
reason: string;
|
|
185
|
+
details?: string;
|
|
186
|
+
}): Promise<ReviewReport>
|
|
141
187
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
// review.status === "pending"
|
|
154
|
-
|
|
155
|
-
// Admin approves it
|
|
156
|
-
await controller.updateReviewStatus(review.id, "approved");
|
|
157
|
-
|
|
158
|
-
// Fetch public ratings for a product page
|
|
159
|
-
const summary = await controller.getProductRatingSummary("prod_abc");
|
|
160
|
-
// { average: 5.0, count: 1, distribution: { "5": 1, "4": 0, ... } }
|
|
161
|
-
|
|
162
|
-
// Fetch approved reviews for display
|
|
163
|
-
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>
|
|
164
198
|
```
|
|
165
199
|
|
|
166
200
|
## Types
|
|
167
201
|
|
|
168
202
|
```ts
|
|
169
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
|
+
}
|
|
170
211
|
|
|
171
212
|
interface Review {
|
|
172
213
|
id: string;
|
|
@@ -180,13 +221,80 @@ interface Review {
|
|
|
180
221
|
status: ReviewStatus;
|
|
181
222
|
isVerifiedPurchase: boolean;
|
|
182
223
|
helpfulCount: number;
|
|
224
|
+
images?: ReviewImage[];
|
|
225
|
+
merchantResponse?: string;
|
|
226
|
+
merchantResponseAt?: Date;
|
|
227
|
+
moderationNote?: string;
|
|
183
228
|
createdAt: Date;
|
|
184
229
|
updatedAt: Date;
|
|
185
230
|
}
|
|
186
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
|
+
|
|
187
249
|
interface RatingSummary {
|
|
188
250
|
average: number;
|
|
189
251
|
count: number;
|
|
190
252
|
distribution: Record<string, number>;
|
|
191
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
|
+
}
|
|
192
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"}
|