@burdenoff/microfe-proserviceworld 2026.625.1 → 2026.626.2

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.
Files changed (31) hide show
  1. package/dist/proserviceworld/pages/AdminReportsPage.js +102 -68
  2. package/dist/proserviceworld/pages/AdminReportsPage.js.map +1 -1
  3. package/dist/proserviceworld/pages/AdminUsersPage.js +37 -33
  4. package/dist/proserviceworld/pages/AdminUsersPage.js.map +1 -1
  5. package/dist/proserviceworld/pages/AnalyticsPage.js +66 -36
  6. package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
  7. package/dist/proserviceworld/pages/BookingsPage.js +52 -48
  8. package/dist/proserviceworld/pages/BookingsPage.js.map +1 -1
  9. package/dist/proserviceworld/pages/DashboardPage.js +275 -243
  10. package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
  11. package/dist/proserviceworld/pages/DocumentsPage.js +204 -200
  12. package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
  13. package/dist/proserviceworld/pages/MessagesPage.js +200 -186
  14. package/dist/proserviceworld/pages/MessagesPage.js.map +1 -1
  15. package/dist/proserviceworld/pages/PaymentsPage.js +70 -39
  16. package/dist/proserviceworld/pages/PaymentsPage.js.map +1 -1
  17. package/dist/proserviceworld/pages/ProjectsPage.js +510 -477
  18. package/dist/proserviceworld/pages/ProjectsPage.js.map +1 -1
  19. package/dist/proserviceworld/pages/ProviderDetailPage.js +71 -41
  20. package/dist/proserviceworld/pages/ProviderDetailPage.js.map +1 -1
  21. package/dist/proserviceworld/pages/ProvidersPage.js +62 -58
  22. package/dist/proserviceworld/pages/ProvidersPage.js.map +1 -1
  23. package/dist/proserviceworld/pages/ReviewsPage.js +80 -63
  24. package/dist/proserviceworld/pages/ReviewsPage.js.map +1 -1
  25. package/dist/proserviceworld/pages/ServiceDetailsPage.js +118 -83
  26. package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +1 -1
  27. package/dist/proserviceworld/pages/ServicesPage.js +134 -130
  28. package/dist/proserviceworld/pages/ServicesPage.js.map +1 -1
  29. package/dist/proserviceworld/pages/VerificationPage.js +23 -19
  30. package/dist/proserviceworld/pages/VerificationPage.js.map +1 -1
  31. package/package.json +2 -2
@@ -2,10 +2,10 @@ import { useProServiceWorldStore as e } from "../store/proserviceworldStore.js";
2
2
  import { useMemo as t, useState as n } from "react";
3
3
  import { ArrowUpDown as r, Award as i, BarChart3 as a, Filter as o, MessageSquare as s, Search as c, Star as l, ThumbsDown as u, ThumbsUp as d, TrendingUp as f } from "lucide-react";
4
4
  import { jsx as p, jsxs as m } from "react/jsx-runtime";
5
- import { Badge as h, Button as g, Card as _, CardContent as v, CardHeader as y, CardTitle as b, Input as x } from "@burdenoff/fe-libs/ui";
5
+ import { AuroraBackground as h, Badge as g, Button as _, Card as v, CardContent as y, CardHeader as b, CardTitle as x, EmphasisPanel as S, GradientText as C, IllustratedEmptyState as w, Input as T, PagePurpose as E } from "@burdenoff/fe-libs/ui";
6
6
  //#region src/proserviceworld/pages/ReviewsPage.tsx
7
- function S() {
8
- let { reviews: S } = e(), [C, w] = n("received"), [T, E] = n(""), [D, O] = n(null), [k, A] = n("date"), [j, M] = n(!1), N = S.length > 0 ? (S.reduce((e, t) => e + t.rating, 0) / S.length).toFixed(1) : "0", P = S.length, F = S.filter((e) => e.rating >= 4).length, I = S.filter((e) => e.rating === 5).length, L = t(() => {
7
+ function D() {
8
+ let { reviews: D } = e(), [O, k] = n("received"), [A, j] = n(""), [M, N] = n(null), [P, F] = n("date"), [I, L] = n(!1), R = D.length > 0 ? (D.reduce((e, t) => e + t.rating, 0) / D.length).toFixed(1) : "0", z = D.length, B = D.filter((e) => e.rating >= 4).length, V = D.filter((e) => e.rating === 5).length, H = t(() => {
9
9
  let e = {
10
10
  5: 0,
11
11
  4: 0,
@@ -13,42 +13,50 @@ function S() {
13
13
  2: 0,
14
14
  1: 0
15
15
  };
16
- for (let t of S) e[t.rating] = (e[t.rating] ?? 0) + 1;
16
+ for (let t of D) e[t.rating] = (e[t.rating] ?? 0) + 1;
17
17
  return e;
18
- }, [S]), R = t(() => {
19
- let e = [...S];
20
- if (T.trim()) {
21
- let t = T.toLowerCase();
18
+ }, [D]), U = t(() => {
19
+ let e = [...D];
20
+ if (A.trim()) {
21
+ let t = A.toLowerCase();
22
22
  e = e.filter((e) => e.comment.toLowerCase().includes(t) || e.clientName.toLowerCase().includes(t) || e.serviceName.toLowerCase().includes(t) || e.providerName.toLowerCase().includes(t));
23
23
  }
24
- return D !== null && (e = e.filter((e) => e.rating === D)), e.sort((e, t) => k === "date" ? new Date(t.createdAt).getTime() - new Date(e.createdAt).getTime() : k === "rating" ? t.rating - e.rating : t.helpful - e.helpful), e;
24
+ return M !== null && (e = e.filter((e) => e.rating === M)), e.sort((e, t) => P === "date" ? new Date(t.createdAt).getTime() - new Date(e.createdAt).getTime() : P === "rating" ? t.rating - e.rating : t.helpful - e.helpful), e;
25
25
  }, [
26
- S,
27
- T,
28
26
  D,
29
- k
30
- ]), z = (e) => Array.from({ length: 5 }, (t, n) => /* @__PURE__ */ p(l, { className: `h-4 w-4 ${n < e ? "fill-status-warning-text text-status-warning-text" : "text-text-secondary/30"}` }, n));
27
+ A,
28
+ M,
29
+ P
30
+ ]), W = (e) => Array.from({ length: 5 }, (t, n) => /* @__PURE__ */ p(l, { className: `h-4 w-4 ${n < e ? "fill-status-warning-text text-status-warning-text" : "text-text-secondary/30"}` }, n));
31
31
  return /* @__PURE__ */ m("div", {
32
- className: "space-y-6 p-6",
32
+ className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
33
33
  children: [
34
34
  /* @__PURE__ */ m("div", {
35
- className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
36
- children: [/* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
37
- className: "text-2xl font-semibold",
38
- children: "Reviews"
39
- }), /* @__PURE__ */ p("p", {
40
- className: "text-sm text-text-secondary",
41
- children: "View and manage your service reviews and ratings."
42
- })] }), /* @__PURE__ */ m(g, {
43
- size: "sm",
44
- onClick: () => M(!0),
45
- children: [/* @__PURE__ */ p(s, { className: "mr-2 h-4 w-4" }), " Write Review"]
46
- })]
35
+ className: "relative overflow-hidden rounded-card -mx-2 px-2 pt-1 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
36
+ children: [
37
+ /* @__PURE__ */ p(h, { intensity: "subtle" }),
38
+ /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("h1", {
39
+ className: "text-2xl font-semibold tracking-tight",
40
+ children: /* @__PURE__ */ p(C, { children: "Reviews" })
41
+ }), /* @__PURE__ */ p("p", {
42
+ className: "text-sm text-text-secondary",
43
+ children: "View and manage your service reviews and ratings."
44
+ })] }),
45
+ /* @__PURE__ */ m(_, {
46
+ size: "sm",
47
+ onClick: () => L(!0),
48
+ children: [/* @__PURE__ */ p(s, { className: "mr-2 h-4 w-4" }), " Write Review"]
49
+ })
50
+ ]
51
+ }),
52
+ /* @__PURE__ */ p(E, {
53
+ icon: /* @__PURE__ */ p(l, { className: "h-4 w-4" }),
54
+ children: "Reviews build the trust that wins work on ProServiceWorld. Track the ratings you have received and given, see how your scores break down star-by-star, and write thoughtful reviews to recognise great providers and clients."
47
55
  }),
48
56
  /* @__PURE__ */ m("div", {
49
57
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
50
58
  children: [
51
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
59
+ /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
52
60
  className: "pt-4",
53
61
  children: /* @__PURE__ */ m("div", {
54
62
  className: "flex items-center gap-3",
@@ -57,14 +65,14 @@ function S() {
57
65
  children: /* @__PURE__ */ p(l, { className: "h-5 w-5 text-status-warning-text" })
58
66
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
59
67
  className: "text-2xl font-bold",
60
- children: N
68
+ children: R
61
69
  }), /* @__PURE__ */ p("p", {
62
70
  className: "text-xs text-text-secondary",
63
71
  children: "Average Rating"
64
72
  })] })]
65
73
  })
66
74
  }) }),
67
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
75
+ /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
68
76
  className: "pt-4",
69
77
  children: /* @__PURE__ */ m("div", {
70
78
  className: "flex items-center gap-3",
@@ -73,14 +81,14 @@ function S() {
73
81
  children: /* @__PURE__ */ p(a, { className: "h-5 w-5 text-accent-blue" })
74
82
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
75
83
  className: "text-2xl font-bold",
76
- children: P
84
+ children: z
77
85
  }), /* @__PURE__ */ p("p", {
78
86
  className: "text-xs text-text-secondary",
79
87
  children: "Total Reviews"
80
88
  })] })]
81
89
  })
82
90
  }) }),
83
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
91
+ /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
84
92
  className: "pt-4",
85
93
  children: /* @__PURE__ */ m("div", {
86
94
  className: "flex items-center gap-3",
@@ -89,14 +97,14 @@ function S() {
89
97
  children: /* @__PURE__ */ p(f, { className: "h-5 w-5 text-status-success-text" })
90
98
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
91
99
  className: "text-2xl font-bold",
92
- children: F
100
+ children: B
93
101
  }), /* @__PURE__ */ p("p", {
94
102
  className: "text-xs text-text-secondary",
95
103
  children: "Positive (4-5 Stars)"
96
104
  })] })]
97
105
  })
98
106
  }) }),
99
- /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
107
+ /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
100
108
  className: "pt-4",
101
109
  children: /* @__PURE__ */ m("div", {
102
110
  className: "flex items-center gap-3",
@@ -105,7 +113,7 @@ function S() {
105
113
  children: /* @__PURE__ */ p(i, { className: "h-5 w-5 text-accent-purple" })
106
114
  }), /* @__PURE__ */ m("div", { children: [/* @__PURE__ */ p("p", {
107
115
  className: "text-2xl font-bold",
108
- children: I
116
+ children: V
109
117
  }), /* @__PURE__ */ p("p", {
110
118
  className: "text-xs text-text-secondary",
111
119
  children: "5-Star Reviews"
@@ -114,10 +122,10 @@ function S() {
114
122
  }) })
115
123
  ]
116
124
  }),
117
- /* @__PURE__ */ m(_, { children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ p(b, {
118
- className: "text-base",
125
+ /* @__PURE__ */ m(S, { children: [/* @__PURE__ */ p("h2", {
126
+ className: "mb-4 text-base font-semibold tracking-tight",
119
127
  children: "Rating Distribution"
120
- }) }), /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p("div", {
128
+ }), /* @__PURE__ */ p("div", { children: /* @__PURE__ */ p("div", {
121
129
  className: "space-y-2",
122
130
  children: [
123
131
  5,
@@ -126,10 +134,10 @@ function S() {
126
134
  2,
127
135
  1
128
136
  ].map((e) => {
129
- let t = L[e] ?? 0, n = P > 0 ? Math.round(t / P * 100) : 0;
137
+ let t = H[e] ?? 0, n = z > 0 ? Math.round(t / z * 100) : 0;
130
138
  return /* @__PURE__ */ m("button", {
131
- onClick: () => O(D === e ? null : e),
132
- className: `flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${D === e ? "bg-action-primary-bg/10" : "hover:bg-bg-sunken/50"}`,
139
+ onClick: () => N(M === e ? null : e),
140
+ className: `flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${M === e ? "bg-action-primary-bg/10" : "hover:bg-bg-sunken/50"}`,
133
141
  children: [
134
142
  /* @__PURE__ */ m("span", {
135
143
  className: "w-12 text-sm font-medium",
@@ -161,17 +169,17 @@ function S() {
161
169
  /* @__PURE__ */ p("div", {
162
170
  className: "flex rounded-lg border",
163
171
  children: ["received", "given"].map((e) => /* @__PURE__ */ p("button", {
164
- onClick: () => w(e),
165
- className: `px-4 py-2 text-sm font-medium transition-colors ${C === e ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:bg-bg-sunken/50"}`,
172
+ onClick: () => k(e),
173
+ className: `px-4 py-2 text-sm font-medium transition-colors ${O === e ? "bg-action-primary-bg text-action-primary-text" : "text-text-secondary hover:bg-bg-sunken/50"}`,
166
174
  children: e === "received" ? "Reviews Received" : "Reviews Given"
167
175
  }, e))
168
176
  }),
169
177
  /* @__PURE__ */ m("div", {
170
178
  className: "relative flex-1",
171
- children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ p(x, {
179
+ children: [/* @__PURE__ */ p(c, { className: "absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary" }), /* @__PURE__ */ p(T, {
172
180
  placeholder: "Search reviews...",
173
- value: T,
174
- onChange: (e) => E(e.target.value),
181
+ value: A,
182
+ onChange: (e) => j(e.target.value),
175
183
  className: "pl-10"
176
184
  })]
177
185
  }),
@@ -191,8 +199,8 @@ function S() {
191
199
  label: "Most Helpful"
192
200
  }
193
201
  ].map(({ field: e, label: t }) => /* @__PURE__ */ m("button", {
194
- onClick: () => A(e),
195
- className: `flex items-center gap-1 rounded border px-3 py-1 text-xs ${k === e ? "border-primary bg-action-primary-bg/5 text-primary" : "text-text-secondary hover:bg-bg-sunken/50"}`,
202
+ onClick: () => F(e),
203
+ className: `flex items-center gap-1 rounded border px-3 py-1 text-xs ${P === e ? "border-primary bg-action-primary-bg/5 text-primary" : "text-text-secondary hover:bg-bg-sunken/50"}`,
196
204
  children: [/* @__PURE__ */ p(r, { className: "h-3 w-3" }), t]
197
205
  }, e))]
198
206
  })
@@ -200,10 +208,19 @@ function S() {
200
208
  }),
201
209
  /* @__PURE__ */ p("div", {
202
210
  className: "space-y-4",
203
- children: R.length === 0 ? /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
204
- className: "py-12 text-center text-text-secondary",
205
- children: "No reviews match your filters."
206
- }) }) : R.map((e) => /* @__PURE__ */ p(_, { children: /* @__PURE__ */ p(v, {
211
+ children: U.length === 0 ? /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
212
+ className: "py-6",
213
+ children: /* @__PURE__ */ p(w, {
214
+ illustration: A || M !== null ? "empty-search" : "empty-notifications",
215
+ title: A || M !== null ? "No reviews match your filters" : "No reviews yet",
216
+ description: A || M !== null ? "Try clearing your search or rating filter to see more reviews." : "Reviews you receive and give will appear here as you complete projects.",
217
+ action: /* @__PURE__ */ m(_, {
218
+ size: "sm",
219
+ onClick: () => L(!0),
220
+ children: [/* @__PURE__ */ p(s, { className: "mr-2 h-4 w-4" }), " Write Review"]
221
+ })
222
+ })
223
+ }) }) : U.map((e) => /* @__PURE__ */ p(v, { children: /* @__PURE__ */ p(y, {
207
224
  className: "pt-6",
208
225
  children: /* @__PURE__ */ m("div", {
209
226
  className: "flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between",
@@ -232,13 +249,13 @@ function S() {
232
249
  children: [
233
250
  /* @__PURE__ */ p("div", {
234
251
  className: "flex",
235
- children: z(e.rating)
252
+ children: W(e.rating)
236
253
  }),
237
254
  /* @__PURE__ */ m("span", {
238
255
  className: "text-sm font-medium",
239
256
  children: [e.rating, ".0"]
240
257
  }),
241
- e.recommended && /* @__PURE__ */ p(h, {
258
+ e.recommended && /* @__PURE__ */ p(g, {
242
259
  variant: "secondary",
243
260
  className: "text-xs",
244
261
  children: "Recommended"
@@ -275,19 +292,19 @@ function S() {
275
292
  })
276
293
  }) }, e.id))
277
294
  }),
278
- j && /* @__PURE__ */ p("div", {
295
+ I && /* @__PURE__ */ p("div", {
279
296
  className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50",
280
- children: /* @__PURE__ */ m(_, {
297
+ children: /* @__PURE__ */ m(v, {
281
298
  className: "mx-4 w-full max-w-lg",
282
- children: [/* @__PURE__ */ p(y, { children: /* @__PURE__ */ m("div", {
299
+ children: [/* @__PURE__ */ p(b, { children: /* @__PURE__ */ m("div", {
283
300
  className: "flex items-center justify-between",
284
- children: [/* @__PURE__ */ p(b, { children: "Write a Review" }), /* @__PURE__ */ p(g, {
301
+ children: [/* @__PURE__ */ p(x, { children: "Write a Review" }), /* @__PURE__ */ p(_, {
285
302
  variant: "outline",
286
303
  size: "sm",
287
- onClick: () => M(!1),
304
+ onClick: () => L(!1),
288
305
  children: "Close"
289
306
  })]
290
- }) }), /* @__PURE__ */ m(v, {
307
+ }) }), /* @__PURE__ */ m(y, {
291
308
  className: "space-y-4",
292
309
  children: [
293
310
  /* @__PURE__ */ m("div", {
@@ -316,12 +333,12 @@ function S() {
316
333
  }),
317
334
  /* @__PURE__ */ m("div", {
318
335
  className: "flex gap-2",
319
- children: [/* @__PURE__ */ p(g, {
336
+ children: [/* @__PURE__ */ p(_, {
320
337
  variant: "outline",
321
338
  className: "flex-1",
322
- onClick: () => M(!1),
339
+ onClick: () => L(!1),
323
340
  children: "Cancel"
324
- }), /* @__PURE__ */ p(g, {
341
+ }), /* @__PURE__ */ p(_, {
325
342
  className: "flex-1",
326
343
  children: "Submit Review"
327
344
  })]
@@ -334,6 +351,6 @@ function S() {
334
351
  });
335
352
  }
336
353
  //#endregion
337
- export { S as ReviewsPage };
354
+ export { D as ReviewsPage };
338
355
 
339
356
  //# sourceMappingURL=ReviewsPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ReviewsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Search,\n ThumbsUp,\n ThumbsDown,\n Filter,\n ArrowUpDown,\n MessageSquare,\n TrendingUp,\n Award,\n BarChart3,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype ViewMode = 'received' | 'given';\ntype SortBy = 'date' | 'rating' | 'helpful';\n\nexport function ReviewsPage() {\n const { reviews } = useProServiceWorldStore();\n const [viewMode, setViewMode] = useState<ViewMode>('received');\n const [searchQuery, setSearchQuery] = useState('');\n const [ratingFilter, setRatingFilter] = useState<number | null>(null);\n const [sortBy, setSortBy] = useState<SortBy>('date');\n const [showWriteModal, setShowWriteModal] = useState(false);\n\n // Stats\n const avgRating =\n reviews.length > 0\n ? (reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length).toFixed(1)\n : '0';\n const totalReviews = reviews.length;\n const positiveReviews = reviews.filter((r) => r.rating >= 4).length;\n const fiveStarCount = reviews.filter((r) => r.rating === 5).length;\n\n // Rating distribution\n const ratingDistribution = useMemo(() => {\n const dist: Record<number, number> = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };\n for (const r of reviews) {\n dist[r.rating] = (dist[r.rating] ?? 0) + 1;\n }\n return dist;\n }, [reviews]);\n\n const filtered = useMemo(() => {\n let result = [...reviews];\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (r) =>\n r.comment.toLowerCase().includes(q) ||\n r.clientName.toLowerCase().includes(q) ||\n r.serviceName.toLowerCase().includes(q) ||\n r.providerName.toLowerCase().includes(q)\n );\n }\n\n if (ratingFilter !== null) {\n result = result.filter((r) => r.rating === ratingFilter);\n }\n\n result.sort((a, b) => {\n if (sortBy === 'date')\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (sortBy === 'rating') return b.rating - a.rating;\n return b.helpful - a.helpful;\n });\n\n return result;\n }, [reviews, searchQuery, ratingFilter, sortBy]);\n\n const renderStars = (rating: number) => {\n return Array.from({ length: 5 }, (_, i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i < rating ? 'fill-status-warning-text text-status-warning-text' : 'text-text-secondary/30'}`}\n />\n ));\n };\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Header */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <div>\n <h1 className=\"text-2xl font-semibold\">Reviews</h1>\n <p className=\"text-sm text-text-secondary\">\n View and manage your service reviews and ratings.\n </p>\n </div>\n <Button size=\"sm\" onClick={() => setShowWriteModal(true)}>\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Write Review\n </Button>\n </div>\n\n {/* Stats Overview */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Star className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{avgRating}</p>\n <p className=\"text-xs text-text-secondary\">Average Rating</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <BarChart3 className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{totalReviews}</p>\n <p className=\"text-xs text-text-secondary\">Total Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <TrendingUp className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{positiveReviews}</p>\n <p className=\"text-xs text-text-secondary\">Positive (4-5 Stars)</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-accent-purple-subtle p-2\">\n <Award className=\"h-5 w-5 text-accent-purple\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{fiveStarCount}</p>\n <p className=\"text-xs text-text-secondary\">5-Star Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Rating Distribution */}\n <Card>\n <CardHeader>\n <CardTitle className=\"text-base\">Rating Distribution</CardTitle>\n </CardHeader>\n <CardContent>\n <div className=\"space-y-2\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = ratingDistribution[star] ?? 0;\n const pct = totalReviews > 0 ? Math.round((count / totalReviews) * 100) : 0;\n return (\n <button\n key={star}\n onClick={() => setRatingFilter(ratingFilter === star ? null : star)}\n className={`flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${\n ratingFilter === star ? 'bg-action-primary-bg/10' : 'hover:bg-bg-sunken/50'\n }`}\n >\n <span className=\"w-12 text-sm font-medium\">{star} star</span>\n <div className=\"flex-1 h-3 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-3 rounded-full bg-status-warning-text transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-16 text-right text-sm text-text-secondary\">\n {count} ({pct}%)\n </span>\n </button>\n );\n })}\n </div>\n </CardContent>\n </Card>\n\n {/* View Toggle + Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <div className=\"flex rounded-lg border\">\n {(['received', 'given'] as const).map((mode) => (\n <button\n key={mode}\n onClick={() => setViewMode(mode)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n viewMode === mode\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n {mode === 'received' ? 'Reviews Received' : 'Reviews Given'}\n </button>\n ))}\n </div>\n\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search reviews...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-text-secondary\" />\n {[\n { field: 'date' as SortBy, label: 'Newest' },\n { field: 'rating' as SortBy, label: 'Highest Rated' },\n { field: 'helpful' as SortBy, label: 'Most Helpful' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => setSortBy(field)}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs ${\n sortBy === field\n ? 'border-primary bg-action-primary-bg/5 text-primary'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n <ArrowUpDown className=\"h-3 w-3\" />\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Review List */}\n <div className=\"space-y-4\">\n {filtered.length === 0 ? (\n <Card>\n <CardContent className=\"py-12 text-center text-text-secondary\">\n No reviews match your filters.\n </CardContent>\n </Card>\n ) : (\n filtered.map((review) => (\n <Card key={review.id}>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {review.clientName.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{review.clientName}</p>\n <p className=\"text-xs text-text-secondary\">\n {review.serviceName} - {review.providerName}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <div className=\"flex\">{renderStars(review.rating)}</div>\n <span className=\"text-sm font-medium\">{review.rating}.0</span>\n {review.recommended && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n Recommended\n </Badge>\n )}\n </div>\n\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n {review.comment}\n </p>\n\n <div className=\"flex flex-wrap gap-4 text-xs text-text-secondary\">\n <span>Project Value: ${review.projectValue.toLocaleString()}</span>\n <span>Duration: {review.projectDuration} days</span>\n <span>{new Date(review.createdAt).toLocaleDateString()}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4 text-sm\">\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-success-text\">\n <ThumbsUp className=\"h-4 w-4\" />\n <span>{review.helpful}</span>\n </button>\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-error-text\">\n <ThumbsDown className=\"h-4 w-4\" />\n <span>{review.notHelpful}</span>\n </button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))\n )}\n </div>\n\n {/* Write Review Modal */}\n {showWriteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n <Card className=\"mx-4 w-full max-w-lg\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Write a Review</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowWriteModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Rating</label>\n <div className=\"flex gap-1\">\n {Array.from({ length: 5 }, (_, i) => (\n <button key={i} className=\"text-text-secondary hover:text-status-warning-text\">\n <Star className=\"h-8 w-8\" />\n </button>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Your Review</label>\n <textarea\n className=\"w-full rounded-md border bg-bg-surface px-3 py-2 text-sm\"\n rows={4}\n placeholder=\"Share your experience with this service...\"\n />\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowWriteModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\">Submit Review</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ReviewsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/ReviewsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n EmphasisPanel,\n AuroraBackground,\n GradientText,\n PagePurpose,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Star,\n Search,\n ThumbsUp,\n ThumbsDown,\n Filter,\n ArrowUpDown,\n MessageSquare,\n TrendingUp,\n Award,\n BarChart3,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\n\ntype ViewMode = 'received' | 'given';\ntype SortBy = 'date' | 'rating' | 'helpful';\n\nexport function ReviewsPage() {\n const { reviews } = useProServiceWorldStore();\n const [viewMode, setViewMode] = useState<ViewMode>('received');\n const [searchQuery, setSearchQuery] = useState('');\n const [ratingFilter, setRatingFilter] = useState<number | null>(null);\n const [sortBy, setSortBy] = useState<SortBy>('date');\n const [showWriteModal, setShowWriteModal] = useState(false);\n\n // Stats\n const avgRating =\n reviews.length > 0\n ? (reviews.reduce((sum, r) => sum + r.rating, 0) / reviews.length).toFixed(1)\n : '0';\n const totalReviews = reviews.length;\n const positiveReviews = reviews.filter((r) => r.rating >= 4).length;\n const fiveStarCount = reviews.filter((r) => r.rating === 5).length;\n\n // Rating distribution\n const ratingDistribution = useMemo(() => {\n const dist: Record<number, number> = { 5: 0, 4: 0, 3: 0, 2: 0, 1: 0 };\n for (const r of reviews) {\n dist[r.rating] = (dist[r.rating] ?? 0) + 1;\n }\n return dist;\n }, [reviews]);\n\n const filtered = useMemo(() => {\n let result = [...reviews];\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (r) =>\n r.comment.toLowerCase().includes(q) ||\n r.clientName.toLowerCase().includes(q) ||\n r.serviceName.toLowerCase().includes(q) ||\n r.providerName.toLowerCase().includes(q)\n );\n }\n\n if (ratingFilter !== null) {\n result = result.filter((r) => r.rating === ratingFilter);\n }\n\n result.sort((a, b) => {\n if (sortBy === 'date')\n return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime();\n if (sortBy === 'rating') return b.rating - a.rating;\n return b.helpful - a.helpful;\n });\n\n return result;\n }, [reviews, searchQuery, ratingFilter, sortBy]);\n\n const renderStars = (rating: number) => {\n return Array.from({ length: 5 }, (_, i) => (\n <Star\n key={i}\n className={`h-4 w-4 ${i < rating ? 'fill-status-warning-text text-status-warning-text' : 'text-text-secondary/30'}`}\n />\n ));\n };\n\n return (\n <div className=\"space-y-6 p-6 bg-bg-canvas min-h-screen\">\n {/* Hero header — the ONE aurora backdrop for this page. */}\n <div className=\"relative overflow-hidden rounded-card -mx-2 px-2 pt-1 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between\">\n <AuroraBackground intensity=\"subtle\" />\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">\n <GradientText>Reviews</GradientText>\n </h1>\n <p className=\"text-sm text-text-secondary\">\n View and manage your service reviews and ratings.\n </p>\n </div>\n <Button size=\"sm\" onClick={() => setShowWriteModal(true)}>\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Write Review\n </Button>\n </div>\n\n <PagePurpose icon={<Star className=\"h-4 w-4\" />}>\n Reviews build the trust that wins work on ProServiceWorld. Track the ratings you have\n received and given, see how your scores break down star-by-star, and write thoughtful\n reviews to recognise great providers and clients.\n </PagePurpose>\n\n {/* Stats Overview */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Star className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{avgRating}</p>\n <p className=\"text-xs text-text-secondary\">Average Rating</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <BarChart3 className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{totalReviews}</p>\n <p className=\"text-xs text-text-secondary\">Total Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <TrendingUp className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{positiveReviews}</p>\n <p className=\"text-xs text-text-secondary\">Positive (4-5 Stars)</p>\n </div>\n </div>\n </CardContent>\n </Card>\n <Card>\n <CardContent className=\"pt-4\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-accent-purple-subtle p-2\">\n <Award className=\"h-5 w-5 text-accent-purple\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{fiveStarCount}</p>\n <p className=\"text-xs text-text-secondary\">5-Star Reviews</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Rating Distribution — the single emphasised insight zone */}\n <EmphasisPanel>\n <h2 className=\"mb-4 text-base font-semibold tracking-tight\">Rating Distribution</h2>\n <div>\n <div className=\"space-y-2\">\n {[5, 4, 3, 2, 1].map((star) => {\n const count = ratingDistribution[star] ?? 0;\n const pct = totalReviews > 0 ? Math.round((count / totalReviews) * 100) : 0;\n return (\n <button\n key={star}\n onClick={() => setRatingFilter(ratingFilter === star ? null : star)}\n className={`flex w-full items-center gap-3 rounded px-2 py-1 transition-colors ${\n ratingFilter === star ? 'bg-action-primary-bg/10' : 'hover:bg-bg-sunken/50'\n }`}\n >\n <span className=\"w-12 text-sm font-medium\">{star} star</span>\n <div className=\"flex-1 h-3 overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-3 rounded-full bg-status-warning-text transition-all\"\n style={{ width: `${pct}%` }}\n />\n </div>\n <span className=\"w-16 text-right text-sm text-text-secondary\">\n {count} ({pct}%)\n </span>\n </button>\n );\n })}\n </div>\n </div>\n </EmphasisPanel>\n\n {/* View Toggle + Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\n <div className=\"flex rounded-lg border\">\n {(['received', 'given'] as const).map((mode) => (\n <button\n key={mode}\n onClick={() => setViewMode(mode)}\n className={`px-4 py-2 text-sm font-medium transition-colors ${\n viewMode === mode\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n {mode === 'received' ? 'Reviews Received' : 'Reviews Given'}\n </button>\n ))}\n </div>\n\n <div className=\"relative flex-1\">\n <Search className=\"absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <Input\n placeholder=\"Search reviews...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-text-secondary\" />\n {[\n { field: 'date' as SortBy, label: 'Newest' },\n { field: 'rating' as SortBy, label: 'Highest Rated' },\n { field: 'helpful' as SortBy, label: 'Most Helpful' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => setSortBy(field)}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs ${\n sortBy === field\n ? 'border-primary bg-action-primary-bg/5 text-primary'\n : 'text-text-secondary hover:bg-bg-sunken/50'\n }`}\n >\n <ArrowUpDown className=\"h-3 w-3\" />\n {label}\n </button>\n ))}\n </div>\n </div>\n\n {/* Review List */}\n <div className=\"space-y-4\">\n {filtered.length === 0 ? (\n <Card>\n <CardContent className=\"py-6\">\n <IllustratedEmptyState\n illustration={\n searchQuery || ratingFilter !== null ? 'empty-search' : 'empty-notifications'\n }\n title={searchQuery || ratingFilter !== null ? 'No reviews match your filters' : 'No reviews yet'}\n description={\n searchQuery || ratingFilter !== null\n ? 'Try clearing your search or rating filter to see more reviews.'\n : 'Reviews you receive and give will appear here as you complete projects.'\n }\n action={\n <Button size=\"sm\" onClick={() => setShowWriteModal(true)}>\n <MessageSquare className=\"mr-2 h-4 w-4\" /> Write Review\n </Button>\n }\n />\n </CardContent>\n </Card>\n ) : (\n filtered.map((review) => (\n <Card key={review.id}>\n <CardContent className=\"pt-6\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex-1 space-y-3\">\n <div className=\"flex items-center gap-3\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-accent-soft font-semibold text-text-primary\">\n {review.clientName.charAt(0)}\n </div>\n <div>\n <p className=\"font-medium\">{review.clientName}</p>\n <p className=\"text-xs text-text-secondary\">\n {review.serviceName} - {review.providerName}\n </p>\n </div>\n </div>\n\n <div className=\"flex items-center gap-2\">\n <div className=\"flex\">{renderStars(review.rating)}</div>\n <span className=\"text-sm font-medium\">{review.rating}.0</span>\n {review.recommended && (\n <Badge variant=\"secondary\" className=\"text-xs\">\n Recommended\n </Badge>\n )}\n </div>\n\n <p className=\"text-sm text-text-secondary leading-relaxed\">\n {review.comment}\n </p>\n\n <div className=\"flex flex-wrap gap-4 text-xs text-text-secondary\">\n <span>Project Value: ${review.projectValue.toLocaleString()}</span>\n <span>Duration: {review.projectDuration} days</span>\n <span>{new Date(review.createdAt).toLocaleDateString()}</span>\n </div>\n </div>\n\n <div className=\"flex items-center gap-4 text-sm\">\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-success-text\">\n <ThumbsUp className=\"h-4 w-4\" />\n <span>{review.helpful}</span>\n </button>\n <button className=\"flex items-center gap-1 text-text-secondary hover:text-status-error-text\">\n <ThumbsDown className=\"h-4 w-4\" />\n <span>{review.notHelpful}</span>\n </button>\n </div>\n </div>\n </CardContent>\n </Card>\n ))\n )}\n </div>\n\n {/* Write Review Modal */}\n {showWriteModal && (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/50\">\n <Card className=\"mx-4 w-full max-w-lg\">\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle>Write a Review</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setShowWriteModal(false)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Rating</label>\n <div className=\"flex gap-1\">\n {Array.from({ length: 5 }, (_, i) => (\n <button key={i} className=\"text-text-secondary hover:text-status-warning-text\">\n <Star className=\"h-8 w-8\" />\n </button>\n ))}\n </div>\n </div>\n <div className=\"space-y-2\">\n <label className=\"text-sm font-medium\">Your Review</label>\n <textarea\n className=\"w-full rounded-md border bg-bg-surface px-3 py-2 text-sm\"\n rows={4}\n placeholder=\"Share your experience with this service...\"\n />\n </div>\n <div className=\"flex gap-2\">\n <Button\n variant=\"outline\"\n className=\"flex-1\"\n onClick={() => setShowWriteModal(false)}\n >\n Cancel\n </Button>\n <Button className=\"flex-1\">Submit Review</Button>\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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"}