@burdenoff/microfe-proserviceworld 2026.624.1 → 2026.625.1
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/dist/proserviceworld/pages/AdminReportsPage.js +365 -332
- package/dist/proserviceworld/pages/AdminReportsPage.js.map +1 -1
- package/dist/proserviceworld/pages/AdminUsersPage.js +257 -237
- package/dist/proserviceworld/pages/AdminUsersPage.js.map +1 -1
- package/dist/proserviceworld/pages/AnalyticsPage.js +343 -315
- package/dist/proserviceworld/pages/AnalyticsPage.js.map +1 -1
- package/dist/proserviceworld/pages/BookingsPage.js +191 -174
- package/dist/proserviceworld/pages/BookingsPage.js.map +1 -1
- package/dist/proserviceworld/pages/DashboardPage.js +383 -346
- package/dist/proserviceworld/pages/DashboardPage.js.map +1 -1
- package/dist/proserviceworld/pages/DocumentsPage.js +383 -318
- package/dist/proserviceworld/pages/DocumentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/MessagesPage.js +70 -75
- package/dist/proserviceworld/pages/MessagesPage.js.map +1 -1
- package/dist/proserviceworld/pages/PaymentsPage.js +367 -340
- package/dist/proserviceworld/pages/PaymentsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProjectsPage.js +428 -381
- package/dist/proserviceworld/pages/ProjectsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProviderDetailPage.js +390 -346
- package/dist/proserviceworld/pages/ProviderDetailPage.js.map +1 -1
- package/dist/proserviceworld/pages/ProvidersPage.js +245 -244
- package/dist/proserviceworld/pages/ProvidersPage.js.map +1 -1
- package/dist/proserviceworld/pages/ReviewsPage.js +14 -14
- package/dist/proserviceworld/pages/ReviewsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServiceDetailsPage.js +338 -305
- package/dist/proserviceworld/pages/ServiceDetailsPage.js.map +1 -1
- package/dist/proserviceworld/pages/ServicesPage.js +156 -153
- package/dist/proserviceworld/pages/ServicesPage.js.map +1 -1
- package/dist/proserviceworld/pages/VerificationPage.js +260 -251
- package/dist/proserviceworld/pages/VerificationPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -2,30 +2,30 @@ 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, Calendar as i, CheckCircle2 as a, ChevronRight as o, Clock as s, DollarSign as c, Filter as l, Loader2 as u, Search as d, User as f, XCircle as p } from "lucide-react";
|
|
4
4
|
import { jsx as m, jsxs as h } from "react/jsx-runtime";
|
|
5
|
-
import { Badge as g, Button as _, Card as v, CardContent as y,
|
|
5
|
+
import { Badge as g, Button as _, Card as v, CardContent as y, GlassCard as b, IllustratedEmptyState as x, Input as S } from "@burdenoff/fe-libs/ui";
|
|
6
6
|
//#region src/proserviceworld/pages/BookingsPage.tsx
|
|
7
7
|
var C = {
|
|
8
8
|
pending: {
|
|
9
9
|
label: "Pending",
|
|
10
|
-
color: "text-
|
|
10
|
+
color: "text-status-warning-text",
|
|
11
11
|
icon: s,
|
|
12
12
|
badgeVariant: "secondary"
|
|
13
13
|
},
|
|
14
14
|
in_progress: {
|
|
15
15
|
label: "In Progress",
|
|
16
|
-
color: "text-blue
|
|
16
|
+
color: "text-accent-blue",
|
|
17
17
|
icon: u,
|
|
18
18
|
badgeVariant: "default"
|
|
19
19
|
},
|
|
20
20
|
completed: {
|
|
21
21
|
label: "Completed",
|
|
22
|
-
color: "text-
|
|
22
|
+
color: "text-status-success-text",
|
|
23
23
|
icon: a,
|
|
24
24
|
badgeVariant: "outline"
|
|
25
25
|
},
|
|
26
26
|
cancelled: {
|
|
27
27
|
label: "Cancelled",
|
|
28
|
-
color: "text-
|
|
28
|
+
color: "text-status-error-text",
|
|
29
29
|
icon: p,
|
|
30
30
|
badgeVariant: "destructive"
|
|
31
31
|
}
|
|
@@ -55,12 +55,12 @@ function w() {
|
|
|
55
55
|
D === e ? A(!k) : (O(e), A(!1));
|
|
56
56
|
};
|
|
57
57
|
return /* @__PURE__ */ h("div", {
|
|
58
|
-
className: "space-y-6 p-6",
|
|
58
|
+
className: "space-y-6 p-6 bg-bg-canvas min-h-screen",
|
|
59
59
|
children: [
|
|
60
60
|
/* @__PURE__ */ h("div", {
|
|
61
61
|
className: "flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between",
|
|
62
62
|
children: [/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h1", {
|
|
63
|
-
className: "text-2xl font-semibold",
|
|
63
|
+
className: "text-2xl font-semibold tracking-tight",
|
|
64
64
|
children: "Bookings"
|
|
65
65
|
}), /* @__PURE__ */ m("p", {
|
|
66
66
|
className: "text-sm text-text-secondary",
|
|
@@ -73,70 +73,75 @@ function w() {
|
|
|
73
73
|
/* @__PURE__ */ h("div", {
|
|
74
74
|
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
75
75
|
children: [
|
|
76
|
-
/* @__PURE__ */ m(
|
|
77
|
-
|
|
76
|
+
/* @__PURE__ */ m(b, {
|
|
77
|
+
treatment: "metric",
|
|
78
|
+
className: "border-border-seam",
|
|
78
79
|
children: /* @__PURE__ */ h("div", {
|
|
79
80
|
className: "flex items-center gap-3",
|
|
80
81
|
children: [/* @__PURE__ */ m("div", {
|
|
81
|
-
className: "rounded-lg bg-
|
|
82
|
-
children: /* @__PURE__ */ m(i, { className: "h-5 w-5 text-blue
|
|
82
|
+
className: "rounded-lg bg-status-info-bg-subtle p-2",
|
|
83
|
+
children: /* @__PURE__ */ m(i, { className: "h-5 w-5 text-accent-blue" })
|
|
83
84
|
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
84
|
-
className: "text-2xl font-bold",
|
|
85
|
+
className: "text-2xl font-bold tabular-nums",
|
|
85
86
|
children: s.length
|
|
86
87
|
}), /* @__PURE__ */ m("p", {
|
|
87
88
|
className: "text-xs text-text-secondary",
|
|
88
89
|
children: "Total Bookings"
|
|
89
90
|
})] })]
|
|
90
91
|
})
|
|
91
|
-
})
|
|
92
|
-
/* @__PURE__ */ m(
|
|
93
|
-
|
|
92
|
+
}),
|
|
93
|
+
/* @__PURE__ */ m(b, {
|
|
94
|
+
treatment: "metric",
|
|
95
|
+
className: "border-border-seam",
|
|
94
96
|
children: /* @__PURE__ */ h("div", {
|
|
95
97
|
className: "flex items-center gap-3",
|
|
96
98
|
children: [/* @__PURE__ */ m("div", {
|
|
97
|
-
className: "rounded-lg bg-
|
|
98
|
-
children: /* @__PURE__ */ m(a, { className: "h-5 w-5 text-
|
|
99
|
+
className: "rounded-lg bg-status-success-bg-subtle p-2",
|
|
100
|
+
children: /* @__PURE__ */ m(a, { className: "h-5 w-5 text-status-success-text" })
|
|
99
101
|
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("p", {
|
|
100
|
-
className: "text-2xl font-bold",
|
|
102
|
+
className: "text-2xl font-bold tabular-nums",
|
|
101
103
|
children: F.completed ?? 0
|
|
102
104
|
}), /* @__PURE__ */ m("p", {
|
|
103
105
|
className: "text-xs text-text-secondary",
|
|
104
106
|
children: "Completed"
|
|
105
107
|
})] })]
|
|
106
108
|
})
|
|
107
|
-
})
|
|
108
|
-
/* @__PURE__ */ m(
|
|
109
|
-
|
|
109
|
+
}),
|
|
110
|
+
/* @__PURE__ */ m(b, {
|
|
111
|
+
treatment: "metric",
|
|
112
|
+
className: "border-border-seam",
|
|
110
113
|
children: /* @__PURE__ */ h("div", {
|
|
111
114
|
className: "flex items-center gap-3",
|
|
112
115
|
children: [/* @__PURE__ */ m("div", {
|
|
113
|
-
className: "rounded-lg bg-
|
|
114
|
-
children: /* @__PURE__ */ m(u, { className: "h-5 w-5 text-
|
|
116
|
+
className: "rounded-lg bg-status-warning-bg-subtle p-2",
|
|
117
|
+
children: /* @__PURE__ */ m(u, { className: "h-5 w-5 text-status-warning-text" })
|
|
115
118
|
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("p", {
|
|
116
|
-
className: "text-2xl font-bold",
|
|
119
|
+
className: "text-2xl font-bold tabular-nums",
|
|
117
120
|
children: [L, "%"]
|
|
118
121
|
}), /* @__PURE__ */ m("p", {
|
|
119
122
|
className: "text-xs text-text-secondary",
|
|
120
123
|
children: "Avg. In-Progress"
|
|
121
124
|
})] })]
|
|
122
125
|
})
|
|
123
|
-
})
|
|
124
|
-
/* @__PURE__ */ m(
|
|
125
|
-
|
|
126
|
+
}),
|
|
127
|
+
/* @__PURE__ */ m(b, {
|
|
128
|
+
treatment: "glass",
|
|
129
|
+
glow: !0,
|
|
130
|
+
className: "border-border-seam",
|
|
126
131
|
children: /* @__PURE__ */ h("div", {
|
|
127
132
|
className: "flex items-center gap-3",
|
|
128
133
|
children: [/* @__PURE__ */ m("div", {
|
|
129
|
-
className: "rounded-lg bg-purple-
|
|
130
|
-
children: /* @__PURE__ */ m(c, { className: "h-5 w-5 text-purple
|
|
134
|
+
className: "rounded-lg bg-accent-purple-subtle p-2",
|
|
135
|
+
children: /* @__PURE__ */ m(c, { className: "h-5 w-5 text-accent-purple" })
|
|
131
136
|
}), /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("p", {
|
|
132
|
-
className: "text-2xl font-bold",
|
|
137
|
+
className: "text-2xl font-bold tabular-nums",
|
|
133
138
|
children: ["$", I.toLocaleString()]
|
|
134
139
|
}), /* @__PURE__ */ m("p", {
|
|
135
140
|
className: "text-xs text-text-secondary",
|
|
136
141
|
children: "Total Budget"
|
|
137
142
|
})] })]
|
|
138
143
|
})
|
|
139
|
-
})
|
|
144
|
+
})
|
|
140
145
|
]
|
|
141
146
|
}),
|
|
142
147
|
/* @__PURE__ */ h("div", {
|
|
@@ -150,7 +155,7 @@ function w() {
|
|
|
150
155
|
className: "pl-10"
|
|
151
156
|
})]
|
|
152
157
|
}), /* @__PURE__ */ h("div", {
|
|
153
|
-
className: "flex items-center gap-2",
|
|
158
|
+
className: "flex flex-wrap items-center gap-2",
|
|
154
159
|
children: [/* @__PURE__ */ m(l, { className: "h-4 w-4 text-text-secondary" }), [
|
|
155
160
|
"all",
|
|
156
161
|
"pending",
|
|
@@ -162,7 +167,7 @@ function w() {
|
|
|
162
167
|
size: "sm",
|
|
163
168
|
onClick: () => E(e),
|
|
164
169
|
children: [e === "all" ? "All" : C[e].label, /* @__PURE__ */ h("span", {
|
|
165
|
-
className: "ml-1 text-xs opacity-70",
|
|
170
|
+
className: "ml-1 text-xs opacity-70 tabular-nums",
|
|
166
171
|
children: [
|
|
167
172
|
"(",
|
|
168
173
|
F[e] ?? 0,
|
|
@@ -173,7 +178,7 @@ function w() {
|
|
|
173
178
|
})]
|
|
174
179
|
}),
|
|
175
180
|
/* @__PURE__ */ m("div", {
|
|
176
|
-
className: "flex gap-2",
|
|
181
|
+
className: "flex flex-wrap gap-2",
|
|
177
182
|
children: [
|
|
178
183
|
{
|
|
179
184
|
field: "date",
|
|
@@ -189,7 +194,8 @@ function w() {
|
|
|
189
194
|
}
|
|
190
195
|
].map(({ field: e, label: t }) => /* @__PURE__ */ h("button", {
|
|
191
196
|
onClick: () => R(e),
|
|
192
|
-
|
|
197
|
+
"aria-pressed": D === e,
|
|
198
|
+
className: `flex items-center gap-1 rounded border px-3 py-1 text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${D === e ? "border-border-strong bg-accent-soft text-text-primary" : "border-border-seam text-text-secondary hover:bg-bg-sunken/50"}`,
|
|
193
199
|
children: [/* @__PURE__ */ m(r, { className: "h-3 w-3" }), t]
|
|
194
200
|
}, e))
|
|
195
201
|
}),
|
|
@@ -197,13 +203,20 @@ function w() {
|
|
|
197
203
|
className: "grid gap-6 lg:grid-cols-3",
|
|
198
204
|
children: [/* @__PURE__ */ m("div", {
|
|
199
205
|
className: `space-y-3 ${P ? "lg:col-span-2" : "lg:col-span-3"}`,
|
|
200
|
-
children: N.length === 0 ? /* @__PURE__ */ m(v, {
|
|
201
|
-
className: "
|
|
202
|
-
children:
|
|
203
|
-
|
|
206
|
+
children: N.length === 0 ? /* @__PURE__ */ m(v, {
|
|
207
|
+
className: "border-border-seam",
|
|
208
|
+
children: /* @__PURE__ */ m(y, {
|
|
209
|
+
className: "py-4",
|
|
210
|
+
children: /* @__PURE__ */ m(x, {
|
|
211
|
+
illustration: "empty-search",
|
|
212
|
+
title: "No bookings found",
|
|
213
|
+
description: "No bookings match your current filters."
|
|
214
|
+
})
|
|
215
|
+
})
|
|
216
|
+
}) : N.map((e) => {
|
|
204
217
|
let t = C[e.status], n = t.icon;
|
|
205
218
|
return /* @__PURE__ */ m(v, {
|
|
206
|
-
className: `cursor-pointer transition-
|
|
219
|
+
className: `cursor-pointer border-border-seam transition-shadow hover:shadow-pop ${j === e.id ? "border-border-strong ring-1 ring-border-focus" : ""}`,
|
|
207
220
|
onClick: () => M(j === e.id ? null : e.id),
|
|
208
221
|
children: /* @__PURE__ */ h(y, {
|
|
209
222
|
className: "pt-4",
|
|
@@ -243,7 +256,7 @@ function w() {
|
|
|
243
256
|
]
|
|
244
257
|
}),
|
|
245
258
|
/* @__PURE__ */ h("span", {
|
|
246
|
-
className: "flex items-center gap-1",
|
|
259
|
+
className: "flex items-center gap-1 tabular-nums",
|
|
247
260
|
children: [
|
|
248
261
|
/* @__PURE__ */ m(c, { className: "h-3 w-3" }),
|
|
249
262
|
" $",
|
|
@@ -261,7 +274,7 @@ function w() {
|
|
|
261
274
|
children: t.label
|
|
262
275
|
}),
|
|
263
276
|
e.status === "in_progress" && /* @__PURE__ */ h("span", {
|
|
264
|
-
className: "text-sm font-medium",
|
|
277
|
+
className: "text-sm font-medium tabular-nums",
|
|
265
278
|
children: [e.progress, "%"]
|
|
266
279
|
}),
|
|
267
280
|
/* @__PURE__ */ m(o, { className: "h-4 w-4 text-text-secondary" })
|
|
@@ -272,7 +285,7 @@ function w() {
|
|
|
272
285
|
children: /* @__PURE__ */ m("div", {
|
|
273
286
|
className: "h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
274
287
|
children: /* @__PURE__ */ m("div", {
|
|
275
|
-
className: "h-2 rounded-full bg-
|
|
288
|
+
className: "h-2 rounded-full bg-action-primary-bg transition-all",
|
|
276
289
|
style: { width: `${e.progress}%` }
|
|
277
290
|
})
|
|
278
291
|
})
|
|
@@ -282,138 +295,142 @@ function w() {
|
|
|
282
295
|
})
|
|
283
296
|
}), P && /* @__PURE__ */ m("div", {
|
|
284
297
|
className: "space-y-4",
|
|
285
|
-
children: /* @__PURE__ */ h(
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
className: "space-y-2 border-t pt-3 text-sm",
|
|
328
|
-
children: [
|
|
329
|
-
/* @__PURE__ */ h("div", {
|
|
330
|
-
className: "flex justify-between",
|
|
331
|
-
children: [/* @__PURE__ */ m("span", {
|
|
332
|
-
className: "text-text-secondary",
|
|
333
|
-
children: "Service"
|
|
334
|
-
}), /* @__PURE__ */ m("span", {
|
|
335
|
-
className: "font-medium",
|
|
336
|
-
children: P.serviceName
|
|
337
|
-
})]
|
|
338
|
-
}),
|
|
339
|
-
/* @__PURE__ */ h("div", {
|
|
340
|
-
className: "flex justify-between",
|
|
341
|
-
children: [/* @__PURE__ */ m("span", {
|
|
342
|
-
className: "text-text-secondary",
|
|
343
|
-
children: "Provider"
|
|
344
|
-
}), /* @__PURE__ */ m("span", {
|
|
345
|
-
className: "font-medium",
|
|
346
|
-
children: P.providerName
|
|
347
|
-
})]
|
|
348
|
-
}),
|
|
349
|
-
/* @__PURE__ */ h("div", {
|
|
350
|
-
className: "flex justify-between",
|
|
351
|
-
children: [/* @__PURE__ */ m("span", {
|
|
352
|
-
className: "text-text-secondary",
|
|
353
|
-
children: "Budget"
|
|
354
|
-
}), /* @__PURE__ */ h("span", {
|
|
355
|
-
className: "font-medium",
|
|
356
|
-
children: ["$", P.budget.toLocaleString()]
|
|
357
|
-
})]
|
|
358
|
-
}),
|
|
359
|
-
/* @__PURE__ */ h("div", {
|
|
360
|
-
className: "flex justify-between",
|
|
361
|
-
children: [/* @__PURE__ */ m("span", {
|
|
362
|
-
className: "text-text-secondary",
|
|
363
|
-
children: "Start Date"
|
|
364
|
-
}), /* @__PURE__ */ m("span", {
|
|
365
|
-
className: "font-medium",
|
|
366
|
-
children: P.startDate
|
|
367
|
-
})]
|
|
368
|
-
}),
|
|
369
|
-
/* @__PURE__ */ h("div", {
|
|
370
|
-
className: "flex justify-between",
|
|
371
|
-
children: [/* @__PURE__ */ m("span", {
|
|
372
|
-
className: "text-text-secondary",
|
|
373
|
-
children: "End Date"
|
|
374
|
-
}), /* @__PURE__ */ m("span", {
|
|
375
|
-
className: "font-medium",
|
|
376
|
-
children: P.endDate
|
|
377
|
-
})]
|
|
378
|
-
}),
|
|
379
|
-
/* @__PURE__ */ h("div", {
|
|
380
|
-
className: "flex justify-between",
|
|
381
|
-
children: [/* @__PURE__ */ m("span", {
|
|
382
|
-
className: "text-text-secondary",
|
|
383
|
-
children: "Payment"
|
|
384
|
-
}), /* @__PURE__ */ m(g, {
|
|
385
|
-
variant: "secondary",
|
|
386
|
-
children: P.paymentStatus
|
|
387
|
-
})]
|
|
388
|
-
}),
|
|
389
|
-
/* @__PURE__ */ h("div", {
|
|
390
|
-
className: "flex justify-between",
|
|
391
|
-
children: [/* @__PURE__ */ m("span", {
|
|
392
|
-
className: "text-text-secondary",
|
|
393
|
-
children: "Method"
|
|
394
|
-
}), /* @__PURE__ */ m("span", {
|
|
395
|
-
className: "font-medium",
|
|
396
|
-
children: P.paymentMethod.replace("_", " ")
|
|
397
|
-
})]
|
|
298
|
+
children: /* @__PURE__ */ h(b, {
|
|
299
|
+
treatment: "glass",
|
|
300
|
+
className: "border-border-seam lg:sticky lg:top-6",
|
|
301
|
+
children: [/* @__PURE__ */ h("div", {
|
|
302
|
+
className: "flex items-center justify-between",
|
|
303
|
+
children: [/* @__PURE__ */ m("h2", {
|
|
304
|
+
className: "text-base font-semibold tracking-tight",
|
|
305
|
+
children: "Booking Details"
|
|
306
|
+
}), /* @__PURE__ */ m(_, {
|
|
307
|
+
variant: "outline",
|
|
308
|
+
size: "sm",
|
|
309
|
+
onClick: () => M(null),
|
|
310
|
+
children: "Close"
|
|
311
|
+
})]
|
|
312
|
+
}), /* @__PURE__ */ h("div", {
|
|
313
|
+
className: "mt-4 space-y-4",
|
|
314
|
+
children: [
|
|
315
|
+
/* @__PURE__ */ h("div", { children: [/* @__PURE__ */ m("h3", {
|
|
316
|
+
className: "font-semibold",
|
|
317
|
+
children: P.title
|
|
318
|
+
}), /* @__PURE__ */ m("p", {
|
|
319
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
320
|
+
children: P.description
|
|
321
|
+
})] }),
|
|
322
|
+
/* @__PURE__ */ m(g, {
|
|
323
|
+
variant: C[P.status].badgeVariant,
|
|
324
|
+
children: C[P.status].label
|
|
325
|
+
}),
|
|
326
|
+
P.status === "in_progress" && /* @__PURE__ */ h("div", { children: [/* @__PURE__ */ h("div", {
|
|
327
|
+
className: "flex items-center justify-between text-sm",
|
|
328
|
+
children: [/* @__PURE__ */ m("span", {
|
|
329
|
+
className: "text-text-secondary",
|
|
330
|
+
children: "Progress"
|
|
331
|
+
}), /* @__PURE__ */ h("span", {
|
|
332
|
+
className: "font-medium tabular-nums",
|
|
333
|
+
children: [P.progress, "%"]
|
|
334
|
+
})]
|
|
335
|
+
}), /* @__PURE__ */ m("div", {
|
|
336
|
+
className: "mt-1 h-2 w-full overflow-hidden rounded-full bg-bg-sunken",
|
|
337
|
+
children: /* @__PURE__ */ m("div", {
|
|
338
|
+
className: "h-2 rounded-full bg-action-primary-bg",
|
|
339
|
+
style: { width: `${P.progress}%` }
|
|
398
340
|
})
|
|
399
|
-
]
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
341
|
+
})] }),
|
|
342
|
+
/* @__PURE__ */ h("div", {
|
|
343
|
+
className: "space-y-2 border-t border-border-seam pt-3 text-sm",
|
|
344
|
+
children: [
|
|
345
|
+
/* @__PURE__ */ h("div", {
|
|
346
|
+
className: "flex justify-between",
|
|
347
|
+
children: [/* @__PURE__ */ m("span", {
|
|
348
|
+
className: "text-text-secondary",
|
|
349
|
+
children: "Service"
|
|
350
|
+
}), /* @__PURE__ */ m("span", {
|
|
351
|
+
className: "font-medium",
|
|
352
|
+
children: P.serviceName
|
|
353
|
+
})]
|
|
354
|
+
}),
|
|
355
|
+
/* @__PURE__ */ h("div", {
|
|
356
|
+
className: "flex justify-between",
|
|
357
|
+
children: [/* @__PURE__ */ m("span", {
|
|
358
|
+
className: "text-text-secondary",
|
|
359
|
+
children: "Provider"
|
|
360
|
+
}), /* @__PURE__ */ m("span", {
|
|
361
|
+
className: "font-medium",
|
|
362
|
+
children: P.providerName
|
|
363
|
+
})]
|
|
364
|
+
}),
|
|
365
|
+
/* @__PURE__ */ h("div", {
|
|
366
|
+
className: "flex justify-between",
|
|
367
|
+
children: [/* @__PURE__ */ m("span", {
|
|
368
|
+
className: "text-text-secondary",
|
|
369
|
+
children: "Budget"
|
|
370
|
+
}), /* @__PURE__ */ h("span", {
|
|
371
|
+
className: "font-medium tabular-nums",
|
|
372
|
+
children: ["$", P.budget.toLocaleString()]
|
|
373
|
+
})]
|
|
374
|
+
}),
|
|
375
|
+
/* @__PURE__ */ h("div", {
|
|
376
|
+
className: "flex justify-between",
|
|
377
|
+
children: [/* @__PURE__ */ m("span", {
|
|
378
|
+
className: "text-text-secondary",
|
|
379
|
+
children: "Start Date"
|
|
380
|
+
}), /* @__PURE__ */ m("span", {
|
|
381
|
+
className: "font-medium",
|
|
382
|
+
children: P.startDate
|
|
383
|
+
})]
|
|
384
|
+
}),
|
|
385
|
+
/* @__PURE__ */ h("div", {
|
|
386
|
+
className: "flex justify-between",
|
|
387
|
+
children: [/* @__PURE__ */ m("span", {
|
|
388
|
+
className: "text-text-secondary",
|
|
389
|
+
children: "End Date"
|
|
390
|
+
}), /* @__PURE__ */ m("span", {
|
|
391
|
+
className: "font-medium",
|
|
392
|
+
children: P.endDate
|
|
393
|
+
})]
|
|
394
|
+
}),
|
|
395
|
+
/* @__PURE__ */ h("div", {
|
|
396
|
+
className: "flex justify-between",
|
|
397
|
+
children: [/* @__PURE__ */ m("span", {
|
|
398
|
+
className: "text-text-secondary",
|
|
399
|
+
children: "Payment"
|
|
400
|
+
}), /* @__PURE__ */ m(g, {
|
|
401
|
+
variant: "secondary",
|
|
402
|
+
children: P.paymentStatus
|
|
403
|
+
})]
|
|
404
|
+
}),
|
|
405
|
+
/* @__PURE__ */ h("div", {
|
|
406
|
+
className: "flex justify-between",
|
|
407
|
+
children: [/* @__PURE__ */ m("span", {
|
|
408
|
+
className: "text-text-secondary",
|
|
409
|
+
children: "Method"
|
|
410
|
+
}), /* @__PURE__ */ m("span", {
|
|
411
|
+
className: "font-medium",
|
|
412
|
+
children: P.paymentMethod.replace("_", " ")
|
|
413
|
+
})]
|
|
414
|
+
})
|
|
415
|
+
]
|
|
416
|
+
}),
|
|
417
|
+
/* @__PURE__ */ h("div", {
|
|
418
|
+
className: "flex gap-2 border-t border-border-seam pt-3",
|
|
419
|
+
children: [/* @__PURE__ */ m(_, {
|
|
420
|
+
className: "flex-1",
|
|
421
|
+
size: "sm",
|
|
422
|
+
variant: "outline",
|
|
423
|
+
children: "Message Provider"
|
|
424
|
+
}), P.status === "pending" && /* @__PURE__ */ m(_, {
|
|
425
|
+
className: "flex-1",
|
|
426
|
+
size: "sm",
|
|
427
|
+
variant: "destructive",
|
|
428
|
+
children: "Cancel"
|
|
429
|
+
})]
|
|
430
|
+
})
|
|
431
|
+
]
|
|
432
|
+
})]
|
|
433
|
+
})
|
|
417
434
|
})]
|
|
418
435
|
})
|
|
419
436
|
]
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BookingsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/BookingsPage.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 Search,\n Clock,\n CheckCircle2,\n XCircle,\n Loader2,\n Calendar,\n DollarSign,\n User,\n ChevronRight,\n Filter,\n ArrowUpDown,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { BookingStatus } from '../types';\n\nconst statusConfig: Record<\n BookingStatus,\n {\n label: string;\n color: string;\n icon: typeof Clock;\n badgeVariant: 'default' | 'secondary' | 'outline' | 'destructive';\n }\n> = {\n pending: { label: 'Pending', color: 'text-yellow-600', icon: Clock, badgeVariant: 'secondary' },\n in_progress: {\n label: 'In Progress',\n color: 'text-blue-600',\n icon: Loader2,\n badgeVariant: 'default',\n },\n completed: {\n label: 'Completed',\n color: 'text-green-600',\n icon: CheckCircle2,\n badgeVariant: 'outline',\n },\n cancelled: {\n label: 'Cancelled',\n color: 'text-red-600',\n icon: XCircle,\n badgeVariant: 'destructive',\n },\n};\n\ntype SortField = 'date' | 'budget' | 'progress';\n\nexport function BookingsPage() {\n const { bookings } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<BookingStatus | 'all'>('all');\n const [sortField, setSortField] = useState<SortField>('date');\n const [sortAsc, setSortAsc] = useState(false);\n const [selectedBookingId, setSelectedBookingId] = useState<string | null>(null);\n\n const filtered = useMemo(() => {\n let result = bookings;\n\n if (statusFilter !== 'all') {\n result = result.filter((b) => b.status === statusFilter);\n }\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (b) =>\n b.title.toLowerCase().includes(q) ||\n b.providerName.toLowerCase().includes(q) ||\n b.serviceName.toLowerCase().includes(q)\n );\n }\n\n result = [...result].sort((a, b) => {\n const cmp =\n sortField === 'date'\n ? new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n : sortField === 'budget'\n ? b.budget - a.budget\n : b.progress - a.progress;\n return sortAsc ? -cmp : cmp;\n });\n\n return result;\n }, [bookings, searchQuery, statusFilter, sortField, sortAsc]);\n\n const selectedBooking = selectedBookingId\n ? bookings.find((b) => b.id === selectedBookingId)\n : null;\n\n const statusCounts = useMemo(() => {\n const counts: Record<string, number> = { all: bookings.length };\n for (const b of bookings) {\n counts[b.status] = (counts[b.status] ?? 0) + 1;\n }\n return counts;\n }, [bookings]);\n\n const totalBudget = bookings.reduce((sum, b) => sum + b.budget, 0);\n const avgProgress = Math.round(\n bookings.filter((b) => b.status === 'in_progress').reduce((sum, b) => sum + b.progress, 0) /\n Math.max(1, bookings.filter((b) => b.status === 'in_progress').length)\n );\n\n const handleSort = (field: SortField) => {\n if (sortField === field) setSortAsc(!sortAsc);\n else {\n setSortField(field);\n setSortAsc(false);\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\">Bookings</h1>\n <p className=\"text-sm text-text-secondary\">\n Manage and track all your service bookings.\n </p>\n </div>\n <Button size=\"sm\">\n <Calendar className=\"mr-2 h-4 w-4\" /> New Booking\n </Button>\n </div>\n\n {/* Stats */}\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-blue-100 p-2 dark:bg-blue-950\">\n <Calendar className=\"h-5 w-5 text-blue-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{bookings.length}</p>\n <p className=\"text-xs text-text-secondary\">Total Bookings</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-green-100 p-2 dark:bg-green-950\">\n <CheckCircle2 className=\"h-5 w-5 text-green-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{statusCounts.completed ?? 0}</p>\n <p className=\"text-xs text-text-secondary\">Completed</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-yellow-100 p-2 dark:bg-yellow-950\">\n <Loader2 className=\"h-5 w-5 text-yellow-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">{avgProgress}%</p>\n <p className=\"text-xs text-text-secondary\">Avg. In-Progress</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-purple-100 p-2 dark:bg-purple-950\">\n <DollarSign className=\"h-5 w-5 text-purple-600\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold\">${totalBudget.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Budget</p>\n </div>\n </div>\n </CardContent>\n </Card>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\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 bookings by title, provider, or service...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n <div className=\"flex items-center gap-2\">\n <Filter className=\"h-4 w-4 text-text-secondary\" />\n {(['all', 'pending', 'in_progress', 'completed', 'cancelled'] as const).map((status) => (\n <Button\n key={status}\n variant={statusFilter === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setStatusFilter(status)}\n >\n {status === 'all' ? 'All' : statusConfig[status].label}\n <span className=\"ml-1 text-xs opacity-70\">({statusCounts[status] ?? 0})</span>\n </Button>\n ))}\n </div>\n </div>\n\n {/* Sort controls */}\n <div className=\"flex gap-2\">\n {[\n { field: 'date' as SortField, label: 'Date' },\n { field: 'budget' as SortField, label: 'Budget' },\n { field: 'progress' as SortField, label: 'Progress' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => handleSort(field)}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs ${\n sortField === 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\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Booking list */}\n <div className={`space-y-3 ${selectedBooking ? 'lg:col-span-2' : 'lg:col-span-3'}`}>\n {filtered.length === 0 ? (\n <Card>\n <CardContent className=\"py-12 text-center text-text-secondary\">\n No bookings match your filters.\n </CardContent>\n </Card>\n ) : (\n filtered.map((booking) => {\n const config = statusConfig[booking.status];\n const StatusIcon = config.icon;\n return (\n <Card\n key={booking.id}\n className={`cursor-pointer transition-colors hover:bg-bg-sunken/30 ${\n selectedBookingId === booking.id ? 'border-primary ring-1 ring-primary' : ''\n }`}\n onClick={() =>\n setSelectedBookingId(selectedBookingId === booking.id ? null : booking.id)\n }\n >\n <CardContent className=\"pt-4\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <StatusIcon className={`h-4 w-4 ${config.color}`} />\n <h3 className=\"font-medium\">{booking.title}</h3>\n </div>\n <p className=\"text-sm text-text-secondary line-clamp-1\">\n {booking.description}\n </p>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <User className=\"h-3 w-3\" /> {booking.providerName}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> {booking.startDate}\n </span>\n <span className=\"flex items-center gap-1\">\n <DollarSign className=\"h-3 w-3\" /> ${booking.budget.toLocaleString()}\n </span>\n </div>\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <Badge variant={config.badgeVariant}>{config.label}</Badge>\n {booking.status === 'in_progress' && (\n <span className=\"text-sm font-medium\">{booking.progress}%</span>\n )}\n <ChevronRight className=\"h-4 w-4 text-text-secondary\" />\n </div>\n </div>\n\n {/* Progress bar for in-progress bookings */}\n {booking.status === 'in_progress' && (\n <div className=\"mt-3\">\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-blue-500 transition-all\"\n style={{ width: `${booking.progress}%` }}\n />\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n );\n })\n )}\n </div>\n\n {/* Detail panel */}\n {selectedBooking && (\n <div className=\"space-y-4\">\n <Card>\n <CardHeader>\n <div className=\"flex items-center justify-between\">\n <CardTitle className=\"text-base\">Booking Details</CardTitle>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setSelectedBookingId(null)}>\n Close\n </Button>\n </div>\n </CardHeader>\n <CardContent className=\"space-y-4\">\n <div>\n <h3 className=\"font-semibold\">{selectedBooking.title}</h3>\n <p className=\"mt-1 text-sm text-text-secondary\">\n {selectedBooking.description}\n </p>\n </div>\n\n <Badge variant={statusConfig[selectedBooking.status].badgeVariant}>\n {statusConfig[selectedBooking.status].label}\n </Badge>\n\n {selectedBooking.status === 'in_progress' && (\n <div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Progress</span>\n <span className=\"font-medium\">{selectedBooking.progress}%</span>\n </div>\n <div className=\"mt-1 h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-blue-500\"\n style={{ width: `${selectedBooking.progress}%` }}\n />\n </div>\n </div>\n )}\n\n <div className=\"space-y-2 border-t pt-3 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service</span>\n <span className=\"font-medium\">{selectedBooking.serviceName}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Provider</span>\n <span className=\"font-medium\">{selectedBooking.providerName}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Budget</span>\n <span className=\"font-medium\">${selectedBooking.budget.toLocaleString()}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Start Date</span>\n <span className=\"font-medium\">{selectedBooking.startDate}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">End Date</span>\n <span className=\"font-medium\">{selectedBooking.endDate}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Payment</span>\n <Badge variant=\"secondary\">{selectedBooking.paymentStatus}</Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Method</span>\n <span className=\"font-medium\">\n {selectedBooking.paymentMethod.replace('_', ' ')}\n </span>\n </div>\n </div>\n\n <div className=\"flex gap-2 border-t pt-3\">\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n Message Provider\n </Button>\n {selectedBooking.status === 'pending' && (\n <Button className=\"flex-1\" size=\"sm\" variant=\"destructive\">\n Cancel\n </Button>\n )}\n </div>\n </CardContent>\n </Card>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"BookingsPage.js","names":[],"sources":["../../../src/proserviceworld/pages/BookingsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport {\n Badge,\n Button,\n Card,\n CardContent,\n CardHeader,\n CardTitle,\n Input,\n GlassCard,\n IllustratedEmptyState,\n} from '@burdenoff/fe-libs/ui';\nimport {\n Search,\n Clock,\n CheckCircle2,\n XCircle,\n Loader2,\n Calendar,\n DollarSign,\n User,\n ChevronRight,\n Filter,\n ArrowUpDown,\n} from 'lucide-react';\nimport { useProServiceWorldStore } from '../store/proserviceworldStore';\nimport type { BookingStatus } from '../types';\n\nconst statusConfig: Record<\n BookingStatus,\n {\n label: string;\n color: string;\n icon: typeof Clock;\n badgeVariant: 'default' | 'secondary' | 'outline' | 'destructive';\n }\n> = {\n pending: {\n label: 'Pending',\n color: 'text-status-warning-text',\n icon: Clock,\n badgeVariant: 'secondary',\n },\n in_progress: {\n label: 'In Progress',\n color: 'text-accent-blue',\n icon: Loader2,\n badgeVariant: 'default',\n },\n completed: {\n label: 'Completed',\n color: 'text-status-success-text',\n icon: CheckCircle2,\n badgeVariant: 'outline',\n },\n cancelled: {\n label: 'Cancelled',\n color: 'text-status-error-text',\n icon: XCircle,\n badgeVariant: 'destructive',\n },\n};\n\ntype SortField = 'date' | 'budget' | 'progress';\n\nexport function BookingsPage() {\n const { bookings } = useProServiceWorldStore();\n const [searchQuery, setSearchQuery] = useState('');\n const [statusFilter, setStatusFilter] = useState<BookingStatus | 'all'>('all');\n const [sortField, setSortField] = useState<SortField>('date');\n const [sortAsc, setSortAsc] = useState(false);\n const [selectedBookingId, setSelectedBookingId] = useState<string | null>(null);\n\n const filtered = useMemo(() => {\n let result = bookings;\n\n if (statusFilter !== 'all') {\n result = result.filter((b) => b.status === statusFilter);\n }\n\n if (searchQuery.trim()) {\n const q = searchQuery.toLowerCase();\n result = result.filter(\n (b) =>\n b.title.toLowerCase().includes(q) ||\n b.providerName.toLowerCase().includes(q) ||\n b.serviceName.toLowerCase().includes(q)\n );\n }\n\n result = [...result].sort((a, b) => {\n const cmp =\n sortField === 'date'\n ? new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\n : sortField === 'budget'\n ? b.budget - a.budget\n : b.progress - a.progress;\n return sortAsc ? -cmp : cmp;\n });\n\n return result;\n }, [bookings, searchQuery, statusFilter, sortField, sortAsc]);\n\n const selectedBooking = selectedBookingId\n ? bookings.find((b) => b.id === selectedBookingId)\n : null;\n\n const statusCounts = useMemo(() => {\n const counts: Record<string, number> = { all: bookings.length };\n for (const b of bookings) {\n counts[b.status] = (counts[b.status] ?? 0) + 1;\n }\n return counts;\n }, [bookings]);\n\n const totalBudget = bookings.reduce((sum, b) => sum + b.budget, 0);\n const avgProgress = Math.round(\n bookings.filter((b) => b.status === 'in_progress').reduce((sum, b) => sum + b.progress, 0) /\n Math.max(1, bookings.filter((b) => b.status === 'in_progress').length)\n );\n\n const handleSort = (field: SortField) => {\n if (sortField === field) setSortAsc(!sortAsc);\n else {\n setSortField(field);\n setSortAsc(false);\n }\n };\n\n return (\n <div className=\"space-y-6 p-6 bg-bg-canvas min-h-screen\">\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 tracking-tight\">Bookings</h1>\n <p className=\"text-sm text-text-secondary\">Manage and track all your service bookings.</p>\n </div>\n <Button size=\"sm\">\n <Calendar className=\"mr-2 h-4 w-4\" /> New Booking\n </Button>\n </div>\n\n {/* Stats */}\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-info-bg-subtle p-2\">\n <Calendar className=\"h-5 w-5 text-accent-blue\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">{bookings.length}</p>\n <p className=\"text-xs text-text-secondary\">Total Bookings</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-success-bg-subtle p-2\">\n <CheckCircle2 className=\"h-5 w-5 text-status-success-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">{statusCounts.completed ?? 0}</p>\n <p className=\"text-xs text-text-secondary\">Completed</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"metric\" className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-status-warning-bg-subtle p-2\">\n <Loader2 className=\"h-5 w-5 text-status-warning-text\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">{avgProgress}%</p>\n <p className=\"text-xs text-text-secondary\">Avg. In-Progress</p>\n </div>\n </div>\n </GlassCard>\n <GlassCard treatment=\"glass\" glow className=\"border-border-seam\">\n <div className=\"flex items-center gap-3\">\n <div className=\"rounded-lg bg-accent-purple-subtle p-2\">\n <DollarSign className=\"h-5 w-5 text-accent-purple\" />\n </div>\n <div>\n <p className=\"text-2xl font-bold tabular-nums\">${totalBudget.toLocaleString()}</p>\n <p className=\"text-xs text-text-secondary\">Total Budget</p>\n </div>\n </div>\n </GlassCard>\n </div>\n\n {/* Filters */}\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-center\">\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 bookings by title, provider, or service...\"\n value={searchQuery}\n onChange={(e) => setSearchQuery(e.target.value)}\n className=\"pl-10\"\n />\n </div>\n <div className=\"flex flex-wrap items-center gap-2\">\n <Filter className=\"h-4 w-4 text-text-secondary\" />\n {(['all', 'pending', 'in_progress', 'completed', 'cancelled'] as const).map((status) => (\n <Button\n key={status}\n variant={statusFilter === status ? 'default' : 'outline'}\n size=\"sm\"\n onClick={() => setStatusFilter(status)}\n >\n {status === 'all' ? 'All' : statusConfig[status].label}\n <span className=\"ml-1 text-xs opacity-70 tabular-nums\">\n ({statusCounts[status] ?? 0})\n </span>\n </Button>\n ))}\n </div>\n </div>\n\n {/* Sort controls */}\n <div className=\"flex flex-wrap gap-2\">\n {[\n { field: 'date' as SortField, label: 'Date' },\n { field: 'budget' as SortField, label: 'Budget' },\n { field: 'progress' as SortField, label: 'Progress' },\n ].map(({ field, label }) => (\n <button\n key={field}\n onClick={() => handleSort(field)}\n aria-pressed={sortField === field}\n className={`flex items-center gap-1 rounded border px-3 py-1 text-xs transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-border-focus ${\n sortField === field\n ? 'border-border-strong bg-accent-soft text-text-primary'\n : 'border-border-seam 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\n <div className=\"grid gap-6 lg:grid-cols-3\">\n {/* Booking list */}\n <div className={`space-y-3 ${selectedBooking ? 'lg:col-span-2' : 'lg:col-span-3'}`}>\n {filtered.length === 0 ? (\n <Card className=\"border-border-seam\">\n <CardContent className=\"py-4\">\n <IllustratedEmptyState\n illustration=\"empty-search\"\n title=\"No bookings found\"\n description=\"No bookings match your current filters.\"\n />\n </CardContent>\n </Card>\n ) : (\n filtered.map((booking) => {\n const config = statusConfig[booking.status];\n const StatusIcon = config.icon;\n return (\n <Card\n key={booking.id}\n className={`cursor-pointer border-border-seam transition-shadow hover:shadow-pop ${\n selectedBookingId === booking.id\n ? 'border-border-strong ring-1 ring-border-focus'\n : ''\n }`}\n onClick={() =>\n setSelectedBookingId(selectedBookingId === booking.id ? null : booking.id)\n }\n >\n <CardContent className=\"pt-4\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"flex-1 space-y-2\">\n <div className=\"flex items-center gap-2\">\n <StatusIcon className={`h-4 w-4 ${config.color}`} />\n <h3 className=\"font-medium\">{booking.title}</h3>\n </div>\n <p className=\"text-sm text-text-secondary line-clamp-1\">\n {booking.description}\n </p>\n <div className=\"flex flex-wrap items-center gap-4 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <User className=\"h-3 w-3\" /> {booking.providerName}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" /> {booking.startDate}\n </span>\n <span className=\"flex items-center gap-1 tabular-nums\">\n <DollarSign className=\"h-3 w-3\" /> ${booking.budget.toLocaleString()}\n </span>\n </div>\n </div>\n <div className=\"flex flex-col items-end gap-2\">\n <Badge variant={config.badgeVariant}>{config.label}</Badge>\n {booking.status === 'in_progress' && (\n <span className=\"text-sm font-medium tabular-nums\">\n {booking.progress}%\n </span>\n )}\n <ChevronRight className=\"h-4 w-4 text-text-secondary\" />\n </div>\n </div>\n\n {/* Progress bar for in-progress bookings */}\n {booking.status === 'in_progress' && (\n <div className=\"mt-3\">\n <div className=\"h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-action-primary-bg transition-all\"\n style={{ width: `${booking.progress}%` }}\n />\n </div>\n </div>\n )}\n </CardContent>\n </Card>\n );\n })\n )}\n </div>\n\n {/* Detail rail */}\n {selectedBooking && (\n <div className=\"space-y-4\">\n <GlassCard treatment=\"glass\" className=\"border-border-seam lg:sticky lg:top-6\">\n <div className=\"flex items-center justify-between\">\n <h2 className=\"text-base font-semibold tracking-tight\">Booking Details</h2>\n <Button variant=\"outline\" size=\"sm\" onClick={() => setSelectedBookingId(null)}>\n Close\n </Button>\n </div>\n <div className=\"mt-4 space-y-4\">\n <div>\n <h3 className=\"font-semibold\">{selectedBooking.title}</h3>\n <p className=\"mt-1 text-sm text-text-secondary\">{selectedBooking.description}</p>\n </div>\n\n <Badge variant={statusConfig[selectedBooking.status].badgeVariant}>\n {statusConfig[selectedBooking.status].label}\n </Badge>\n\n {selectedBooking.status === 'in_progress' && (\n <div>\n <div className=\"flex items-center justify-between text-sm\">\n <span className=\"text-text-secondary\">Progress</span>\n <span className=\"font-medium tabular-nums\">{selectedBooking.progress}%</span>\n </div>\n <div className=\"mt-1 h-2 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div\n className=\"h-2 rounded-full bg-action-primary-bg\"\n style={{ width: `${selectedBooking.progress}%` }}\n />\n </div>\n </div>\n )}\n\n <div className=\"space-y-2 border-t border-border-seam pt-3 text-sm\">\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Service</span>\n <span className=\"font-medium\">{selectedBooking.serviceName}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Provider</span>\n <span className=\"font-medium\">{selectedBooking.providerName}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Budget</span>\n <span className=\"font-medium tabular-nums\">\n ${selectedBooking.budget.toLocaleString()}\n </span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Start Date</span>\n <span className=\"font-medium\">{selectedBooking.startDate}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">End Date</span>\n <span className=\"font-medium\">{selectedBooking.endDate}</span>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Payment</span>\n <Badge variant=\"secondary\">{selectedBooking.paymentStatus}</Badge>\n </div>\n <div className=\"flex justify-between\">\n <span className=\"text-text-secondary\">Method</span>\n <span className=\"font-medium\">\n {selectedBooking.paymentMethod.replace('_', ' ')}\n </span>\n </div>\n </div>\n\n <div className=\"flex gap-2 border-t border-border-seam pt-3\">\n <Button className=\"flex-1\" size=\"sm\" variant=\"outline\">\n Message Provider\n </Button>\n {selectedBooking.status === 'pending' && (\n <Button className=\"flex-1\" size=\"sm\" variant=\"destructive\">\n Cancel\n </Button>\n )}\n </div>\n </div>\n </GlassCard>\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|