@burdenoff/microfe-housingvista 2026.709.2 → 2026.709.3

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 (83) hide show
  1. package/dist/housingvista/HousingVistaRoutes.d.ts.map +1 -1
  2. package/dist/housingvista/HousingVistaRoutes.js +136 -37
  3. package/dist/housingvista/HousingVistaRoutes.js.map +1 -1
  4. package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts +1 -1
  5. package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts.map +1 -1
  6. package/dist/housingvista/hooks/useHousingVistaAnalytics.js +4 -4
  7. package/dist/housingvista/hooks/useHousingVistaAnalytics.js.map +1 -1
  8. package/dist/housingvista/pages/amc/AMCManagementPage.d.ts.map +1 -1
  9. package/dist/housingvista/pages/amc/AMCManagementPage.js +62 -60
  10. package/dist/housingvista/pages/amc/AMCManagementPage.js.map +1 -1
  11. package/dist/housingvista/pages/assets/AssetDetailPage.d.ts.map +1 -1
  12. package/dist/housingvista/pages/assets/AssetDetailPage.js +141 -138
  13. package/dist/housingvista/pages/assets/AssetDetailPage.js.map +1 -1
  14. package/dist/housingvista/pages/assets/AssetManagementPage.d.ts.map +1 -1
  15. package/dist/housingvista/pages/assets/AssetManagementPage.js +193 -191
  16. package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
  17. package/dist/housingvista/pages/chat/ChatPage.d.ts.map +1 -1
  18. package/dist/housingvista/pages/chat/ChatPage.js +115 -113
  19. package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
  20. package/dist/housingvista/pages/finance/HomeLoanDetailPage.d.ts.map +1 -1
  21. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js +152 -149
  22. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js.map +1 -1
  23. package/dist/housingvista/pages/finance/HomeLoansPage.d.ts.map +1 -1
  24. package/dist/housingvista/pages/finance/HomeLoansPage.js +141 -139
  25. package/dist/housingvista/pages/finance/HomeLoansPage.js.map +1 -1
  26. package/dist/housingvista/pages/investments/InvestmentDetailPage.d.ts.map +1 -1
  27. package/dist/housingvista/pages/investments/InvestmentDetailPage.js +290 -287
  28. package/dist/housingvista/pages/investments/InvestmentDetailPage.js.map +1 -1
  29. package/dist/housingvista/pages/investments/InvestmentsPage.d.ts.map +1 -1
  30. package/dist/housingvista/pages/investments/InvestmentsPage.js +64 -62
  31. package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
  32. package/dist/housingvista/pages/legal/LegalPage.d.ts.map +1 -1
  33. package/dist/housingvista/pages/legal/LegalPage.js +95 -93
  34. package/dist/housingvista/pages/legal/LegalPage.js.map +1 -1
  35. package/dist/housingvista/pages/legal/LegalServiceDetailPage.d.ts.map +1 -1
  36. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js +129 -126
  37. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js.map +1 -1
  38. package/dist/housingvista/pages/market/AreaInsightsPage.d.ts.map +1 -1
  39. package/dist/housingvista/pages/market/AreaInsightsPage.js +99 -97
  40. package/dist/housingvista/pages/market/AreaInsightsPage.js.map +1 -1
  41. package/dist/housingvista/pages/market/MarketAnalyticsPage.d.ts.map +1 -1
  42. package/dist/housingvista/pages/market/MarketAnalyticsPage.js +138 -136
  43. package/dist/housingvista/pages/market/MarketAnalyticsPage.js.map +1 -1
  44. package/dist/housingvista/pages/marketplace/MarketplacePage.d.ts.map +1 -1
  45. package/dist/housingvista/pages/marketplace/MarketplacePage.js +99 -97
  46. package/dist/housingvista/pages/marketplace/MarketplacePage.js.map +1 -1
  47. package/dist/housingvista/pages/marketplace/ServiceDetailPage.d.ts.map +1 -1
  48. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js +137 -134
  49. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js.map +1 -1
  50. package/dist/housingvista/pages/offers/OffersPage.d.ts.map +1 -1
  51. package/dist/housingvista/pages/offers/OffersPage.js +94 -92
  52. package/dist/housingvista/pages/offers/OffersPage.js.map +1 -1
  53. package/dist/housingvista/pages/properties/AddPropertyPage.d.ts.map +1 -1
  54. package/dist/housingvista/pages/properties/AddPropertyPage.js +280 -279
  55. package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
  56. package/dist/housingvista/pages/rental/RentalManagementPage.d.ts.map +1 -1
  57. package/dist/housingvista/pages/rental/RentalManagementPage.js +153 -151
  58. package/dist/housingvista/pages/rental/RentalManagementPage.js.map +1 -1
  59. package/dist/housingvista/pages/settings/ProfilePage.d.ts.map +1 -1
  60. package/dist/housingvista/pages/settings/ProfilePage.js +52 -50
  61. package/dist/housingvista/pages/settings/ProfilePage.js.map +1 -1
  62. package/dist/housingvista/pages/settings/SettingsPage.d.ts.map +1 -1
  63. package/dist/housingvista/pages/settings/SettingsPage.js +54 -52
  64. package/dist/housingvista/pages/settings/SettingsPage.js.map +1 -1
  65. package/dist/housingvista/pages/shortlist/ShortlistPage.d.ts.map +1 -1
  66. package/dist/housingvista/pages/shortlist/ShortlistPage.js +43 -41
  67. package/dist/housingvista/pages/shortlist/ShortlistPage.js.map +1 -1
  68. package/dist/housingvista/pages/transactions/TransactionDetailPage.d.ts.map +1 -1
  69. package/dist/housingvista/pages/transactions/TransactionDetailPage.js +211 -208
  70. package/dist/housingvista/pages/transactions/TransactionDetailPage.js.map +1 -1
  71. package/dist/housingvista/pages/transactions/TransactionsPage.d.ts.map +1 -1
  72. package/dist/housingvista/pages/transactions/TransactionsPage.js +85 -83
  73. package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
  74. package/dist/housingvista/pages/verification/VerificationDetailPage.d.ts.map +1 -1
  75. package/dist/housingvista/pages/verification/VerificationDetailPage.js +25 -22
  76. package/dist/housingvista/pages/verification/VerificationDetailPage.js.map +1 -1
  77. package/dist/housingvista/pages/verification/VerificationPage.d.ts.map +1 -1
  78. package/dist/housingvista/pages/verification/VerificationPage.js +123 -121
  79. package/dist/housingvista/pages/verification/VerificationPage.js.map +1 -1
  80. package/dist/housingvista/pages/viewings/ViewingsPage.d.ts.map +1 -1
  81. package/dist/housingvista/pages/viewings/ViewingsPage.js +128 -126
  82. package/dist/housingvista/pages/viewings/ViewingsPage.js.map +1 -1
  83. package/package.json +1 -1
@@ -3,15 +3,16 @@ import { PageLayout as n } from "../../components/PageLayout.js";
3
3
  import { DataTable as r } from "../../components/DataTable.js";
4
4
  import { StatusBadge as i } from "../../components/StatusBadge.js";
5
5
  import { FilterBar as a } from "../../components/FilterBar.js";
6
- import { useApproveVerification as o, useRejectVerification as s, useVerifications as c } from "../../hooks/index.js";
7
- import { notify as l } from "../../lib/toast.js";
6
+ import { useTrackPageView as o } from "../../hooks/useHousingVistaAnalytics.js";
7
+ import { useApproveVerification as s, useRejectVerification as c, useVerifications as l } from "../../hooks/index.js";
8
+ import { notify as u } from "../../lib/toast.js";
8
9
  import "../../components/index.js";
9
- import { useServerPagination as u } from "../../hooks/useServerPagination.js";
10
- import { useEffect as d, useState as f } from "react";
11
- import { Check as p, CheckCircle as m, Clock as h, Eye as g, Shield as _, X as v, XCircle as y } from "lucide-react";
12
- import { useNavigate as b } from "react-router-dom";
13
- import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
14
- import { Button as w, EmphasisPanel as ee, ResponsiveDialog as te, ResponsiveDialogContent as ne, ResponsiveDialogDescription as re, ResponsiveDialogFooter as ie, ResponsiveDialogHeader as ae, ResponsiveDialogTitle as oe } from "@burdenoff/fe-libs/ui";
10
+ import { useServerPagination as ee } from "../../hooks/useServerPagination.js";
11
+ import { useEffect as te, useState as d } from "react";
12
+ import { Check as ne, CheckCircle as re, Clock as f, Eye as ie, Shield as p, X as m, XCircle as h } from "lucide-react";
13
+ import { useNavigate as g } from "react-router-dom";
14
+ import { Fragment as _, jsx as v, jsxs as y } from "react/jsx-runtime";
15
+ import { Button as b, EmphasisPanel as x, ResponsiveDialog as S, ResponsiveDialogContent as C, ResponsiveDialogDescription as w, ResponsiveDialogFooter as T, ResponsiveDialogHeader as ae, ResponsiveDialogTitle as oe } from "@burdenoff/fe-libs/ui";
15
16
  //#region src/housingvista/pages/verification/VerificationPage.tsx
16
17
  function se(e) {
17
18
  switch (e) {
@@ -28,18 +29,18 @@ function ce(e) {
28
29
  function le(e) {
29
30
  return e.replace("_", " ").replace(/\b\w/g, (e) => e.toUpperCase());
30
31
  }
31
- function T(t) {
32
+ function E(t) {
32
33
  let n = {
33
34
  high: "bg-status-error-bg-subtle text-status-error-text",
34
35
  medium: "bg-status-warning-bg-subtle text-status-warning-text",
35
36
  low: "bg-status-success-bg-subtle text-status-success-text"
36
37
  };
37
- return /* @__PURE__ */ S("span", {
38
+ return /* @__PURE__ */ v("span", {
38
39
  className: e("inline-flex rounded-full px-2 py-0.5 text-xs font-medium capitalize", n[t] ?? n.low),
39
40
  children: t
40
41
  });
41
42
  }
42
- var E = [
43
+ var D = [
43
44
  {
44
45
  value: "",
45
46
  label: "All statuses"
@@ -60,7 +61,7 @@ var E = [
60
61
  value: "rejected",
61
62
  label: "Rejected"
62
63
  }
63
- ], D = [
64
+ ], O = [
64
65
  {
65
66
  value: "",
66
67
  label: "All priorities"
@@ -77,7 +78,7 @@ var E = [
77
78
  value: "low",
78
79
  label: "Low"
79
80
  }
80
- ], O = [
81
+ ], k = [
81
82
  {
82
83
  value: "",
83
84
  label: "All types"
@@ -102,8 +103,8 @@ var E = [
102
103
  value: "bank_account",
103
104
  label: "Bank Account"
104
105
  }
105
- ], k = "h-9 rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
106
- function A({ label: t, value: n, total: r, tone: i, icon: a }) {
106
+ ], A = "h-9 rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]";
107
+ function j({ label: t, value: n, total: r, tone: i, icon: a }) {
107
108
  let o = r > 0 ? Math.round(n / r * 100) : 0, s = {
108
109
  success: "bg-status-success-text",
109
110
  warning: "bg-status-warning-text",
@@ -115,26 +116,26 @@ function A({ label: t, value: n, total: r, tone: i, icon: a }) {
115
116
  error: "bg-status-error-bg-subtle text-status-error-text",
116
117
  info: "bg-status-info-bg-subtle text-status-info-text"
117
118
  }[i];
118
- return /* @__PURE__ */ C("div", {
119
+ return /* @__PURE__ */ y("div", {
119
120
  className: "rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1",
120
121
  children: [
121
- /* @__PURE__ */ C("div", {
122
+ /* @__PURE__ */ y("div", {
122
123
  className: "flex items-center justify-between",
123
- children: [/* @__PURE__ */ S("span", {
124
+ children: [/* @__PURE__ */ v("span", {
124
125
  className: "text-2xl font-bold tabular-nums text-text-primary",
125
126
  children: n
126
- }), /* @__PURE__ */ S("span", {
127
+ }), /* @__PURE__ */ v("span", {
127
128
  className: e("flex h-8 w-8 items-center justify-center rounded-lg", c),
128
129
  children: a
129
130
  })]
130
131
  }),
131
- /* @__PURE__ */ S("p", {
132
+ /* @__PURE__ */ v("p", {
132
133
  className: "mt-0.5 text-sm font-medium text-text-secondary",
133
134
  children: t
134
135
  }),
135
- /* @__PURE__ */ S("div", {
136
+ /* @__PURE__ */ v("div", {
136
137
  className: "mt-3 h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken",
137
- children: /* @__PURE__ */ S("div", {
138
+ children: /* @__PURE__ */ v("div", {
138
139
  className: e("h-full rounded-full transition-all", s),
139
140
  style: { width: `${o}%` }
140
141
  })
@@ -142,46 +143,47 @@ function A({ label: t, value: n, total: r, tone: i, icon: a }) {
142
143
  ]
143
144
  });
144
145
  }
145
- function j() {
146
- let e = b(), j = u(10), [M, N] = f(""), [P, F] = f(""), [I, L] = f(""), [R, z] = f(""), [B, ue] = f(""), { setPage: V } = j;
147
- d(() => {
146
+ function M() {
147
+ o("housingvista.verification.viewed");
148
+ let e = g(), M = ee(10), [N, P] = d(""), [F, I] = d(""), [L, R] = d(""), [z, B] = d(""), [V, H] = d(""), { setPage: U } = M;
149
+ te(() => {
148
150
  let e = setTimeout(() => {
149
- F(M.trim()), V(1);
151
+ I(N.trim()), U(1);
150
152
  }, 300);
151
153
  return () => clearTimeout(e);
152
- }, [M, V]);
153
- let { data: H, loading: U } = c({
154
+ }, [N, U]);
155
+ let { data: W, loading: ue } = l({
154
156
  filter: {
155
- search: P || void 0,
156
- status: I || void 0,
157
- priority: R || void 0,
158
- entityType: B || void 0
157
+ search: F || void 0,
158
+ status: L || void 0,
159
+ priority: z || void 0,
160
+ entityType: V || void 0
159
161
  },
160
- pagination: j.pagination
161
- }), { approveVerification: de, loading: fe } = o(), { rejectVerification: pe, loading: me } = s(), [W, G] = f(null), [K, q] = f(""), J = fe || me, Y = (e, t) => {
162
- G({
162
+ pagination: M.pagination
163
+ }), { approveVerification: de, loading: fe } = s(), { rejectVerification: pe, loading: me } = c(), [G, K] = d(null), [q, J] = d(""), Y = fe || me, X = (e, t) => {
164
+ K({
163
165
  item: e,
164
166
  mode: t
165
- }), q("");
166
- }, X = () => {
167
- J || (G(null), q(""));
167
+ }), J("");
168
+ }, Z = () => {
169
+ Y || (K(null), J(""));
168
170
  }, he = async (e) => {
169
- if (e.preventDefault(), !W) return;
170
- let t = K.trim() || void 0;
171
+ if (e.preventDefault(), !G) return;
172
+ let t = q.trim() || void 0;
171
173
  try {
172
- W.mode === "approve" ? (await de(W.item.id, t), l.success("Verification approved", W.item.entityLabel)) : (await pe(W.item.id, t), l.success("Verification rejected", W.item.entityLabel)), G(null), q("");
174
+ G.mode === "approve" ? (await de(G.item.id, t), u.success("Verification approved", G.item.entityLabel)) : (await pe(G.item.id, t), u.success("Verification rejected", G.item.entityLabel)), K(null), J("");
173
175
  } catch (e) {
174
176
  let t = e instanceof Error ? e.message : "Please try again.";
175
- l.error(W.mode === "approve" ? "Could not approve verification" : "Could not reject verification", t);
177
+ u.error(G.mode === "approve" ? "Could not approve verification" : "Could not reject verification", t);
176
178
  }
177
- }, ge = H.filter((e) => e.status === "verified").length, _e = H.filter((e) => e.status === "pending").length, ve = H.filter((e) => e.status === "in_progress").length, Z = H.filter((e) => e.status === "rejected").length, Q = H.length, ye = [
179
+ }, ge = W.filter((e) => e.status === "verified").length, _e = W.filter((e) => e.status === "pending").length, ve = W.filter((e) => e.status === "in_progress").length, ye = W.filter((e) => e.status === "rejected").length, Q = W.length, be = [
178
180
  {
179
181
  key: "entityLabel",
180
182
  header: "Item",
181
- render: (e) => /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("p", {
183
+ render: (e) => /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("p", {
182
184
  className: "font-medium text-text-primary",
183
185
  children: e.entityLabel
184
- }), e.notes && /* @__PURE__ */ S("p", {
186
+ }), e.notes && /* @__PURE__ */ v("p", {
185
187
  className: "mt-0.5 text-xs text-text-secondary line-clamp-1",
186
188
  children: e.notes
187
189
  })] })
@@ -189,7 +191,7 @@ function j() {
189
191
  {
190
192
  key: "entityType",
191
193
  header: "Type",
192
- render: (e) => /* @__PURE__ */ S("span", {
194
+ render: (e) => /* @__PURE__ */ v("span", {
193
195
  className: "inline-flex items-center gap-1 text-xs text-text-secondary capitalize",
194
196
  children: le(e.entityType)
195
197
  })
@@ -197,12 +199,12 @@ function j() {
197
199
  {
198
200
  key: "priority",
199
201
  header: "Priority",
200
- render: (e) => T(e.priority)
202
+ render: (e) => E(e.priority)
201
203
  },
202
204
  {
203
205
  key: "submittedDate",
204
206
  header: "Submitted",
205
- render: (e) => /* @__PURE__ */ S("span", {
207
+ render: (e) => /* @__PURE__ */ v("span", {
206
208
  className: "text-sm text-text-secondary",
207
209
  children: t(e.submittedDate)
208
210
  })
@@ -210,7 +212,7 @@ function j() {
210
212
  {
211
213
  key: "status",
212
214
  header: "Status",
213
- render: (e) => /* @__PURE__ */ S(i, {
215
+ render: (e) => /* @__PURE__ */ v(i, {
214
216
  label: ce(e.status),
215
217
  variant: se(e.status),
216
218
  dot: !0
@@ -222,178 +224,178 @@ function j() {
222
224
  sortable: !1,
223
225
  render: (t) => {
224
226
  let n = t.status === "pending" || t.status === "in_progress";
225
- return /* @__PURE__ */ C("div", {
227
+ return /* @__PURE__ */ y("div", {
226
228
  className: "flex items-center gap-1.5",
227
- children: [/* @__PURE__ */ C("button", {
229
+ children: [/* @__PURE__ */ y("button", {
228
230
  onClick: (n) => {
229
231
  n.stopPropagation(), e(`../verification/${t.id}`);
230
232
  },
231
233
  className: "inline-flex items-center gap-1 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken",
232
- children: [/* @__PURE__ */ S(g, { className: "h-3 w-3" }), "View"]
233
- }), n && /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ C("button", {
234
+ children: [/* @__PURE__ */ v(ie, { className: "h-3 w-3" }), "View"]
235
+ }), n && /* @__PURE__ */ y(_, { children: [/* @__PURE__ */ y("button", {
234
236
  onClick: (e) => {
235
- e.stopPropagation(), Y(t, "approve");
237
+ e.stopPropagation(), X(t, "approve");
236
238
  },
237
239
  className: "inline-flex items-center gap-1 rounded-md border border-status-success-border bg-status-success-bg-subtle px-2.5 py-1 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle/70",
238
- children: [/* @__PURE__ */ S(p, { className: "h-3 w-3" }), "Approve"]
239
- }), /* @__PURE__ */ C("button", {
240
+ children: [/* @__PURE__ */ v(ne, { className: "h-3 w-3" }), "Approve"]
241
+ }), /* @__PURE__ */ y("button", {
240
242
  onClick: (e) => {
241
- e.stopPropagation(), Y(t, "reject");
243
+ e.stopPropagation(), X(t, "reject");
242
244
  },
243
245
  className: "inline-flex items-center gap-1 rounded-md border border-status-error-border bg-status-error-bg-subtle px-2.5 py-1 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle/70",
244
- children: [/* @__PURE__ */ S(v, { className: "h-3 w-3" }), "Reject"]
246
+ children: [/* @__PURE__ */ v(m, { className: "h-3 w-3" }), "Reject"]
245
247
  })] })]
246
248
  });
247
249
  }
248
250
  }
249
- ], $ = W?.mode === "approve";
250
- return /* @__PURE__ */ C(n, {
251
+ ], $ = G?.mode === "approve";
252
+ return /* @__PURE__ */ y(n, {
251
253
  title: "Verification Center",
252
254
  description: "Track and manage all your verification requests",
253
255
  purpose: "Submit and monitor identity, ownership, and document checks that build trust in your listings and deals. Use this page to see what is verified, what is still pending, and what was rejected so you can act before it blocks a transaction.",
254
- actions: /* @__PURE__ */ C("span", {
256
+ actions: /* @__PURE__ */ y("span", {
255
257
  className: "inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-3 py-1.5 text-xs font-medium text-status-success-text",
256
- children: [/* @__PURE__ */ S(_, { className: "h-3.5 w-3.5" }), "Trust & Safety"]
258
+ children: [/* @__PURE__ */ v(p, { className: "h-3.5 w-3.5" }), "Trust & Safety"]
257
259
  }),
258
260
  children: [
259
- /* @__PURE__ */ S(ee, {
261
+ /* @__PURE__ */ v(x, {
260
262
  className: "p-4",
261
- children: /* @__PURE__ */ C("div", {
263
+ children: /* @__PURE__ */ y("div", {
262
264
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
263
265
  children: [
264
- /* @__PURE__ */ S(A, {
266
+ /* @__PURE__ */ v(j, {
265
267
  label: "Verified",
266
268
  value: ge,
267
269
  total: Q,
268
270
  tone: "success",
269
- icon: /* @__PURE__ */ S(m, { className: "h-4 w-4" })
271
+ icon: /* @__PURE__ */ v(re, { className: "h-4 w-4" })
270
272
  }),
271
- /* @__PURE__ */ S(A, {
273
+ /* @__PURE__ */ v(j, {
272
274
  label: "Pending",
273
275
  value: _e + ve,
274
276
  total: Q,
275
277
  tone: "warning",
276
- icon: /* @__PURE__ */ S(h, { className: "h-4 w-4" })
278
+ icon: /* @__PURE__ */ v(f, { className: "h-4 w-4" })
277
279
  }),
278
- /* @__PURE__ */ S(A, {
280
+ /* @__PURE__ */ v(j, {
279
281
  label: "Rejected",
280
- value: Z,
282
+ value: ye,
281
283
  total: Q,
282
284
  tone: "error",
283
- icon: /* @__PURE__ */ S(y, { className: "h-4 w-4" })
285
+ icon: /* @__PURE__ */ v(h, { className: "h-4 w-4" })
284
286
  }),
285
- /* @__PURE__ */ S(A, {
287
+ /* @__PURE__ */ v(j, {
286
288
  label: "Total",
287
289
  value: Q,
288
290
  total: Q,
289
291
  tone: "info",
290
- icon: /* @__PURE__ */ S(_, { className: "h-4 w-4" })
292
+ icon: /* @__PURE__ */ v(p, { className: "h-4 w-4" })
291
293
  })
292
294
  ]
293
295
  })
294
296
  }),
295
- /* @__PURE__ */ C("div", { children: [
296
- /* @__PURE__ */ S("h2", {
297
+ /* @__PURE__ */ y("div", { children: [
298
+ /* @__PURE__ */ v("h2", {
297
299
  className: "mb-3 text-lg font-semibold text-text-primary",
298
300
  children: "Verification Items"
299
301
  }),
300
- /* @__PURE__ */ S(a, {
302
+ /* @__PURE__ */ v(a, {
301
303
  className: "mb-4",
302
- searchValue: M,
303
- onSearchChange: N,
304
+ searchValue: N,
305
+ onSearchChange: P,
304
306
  searchPlaceholder: "Search verification items...",
305
- filters: /* @__PURE__ */ C(x, { children: [
306
- /* @__PURE__ */ S("select", {
307
+ filters: /* @__PURE__ */ y(_, { children: [
308
+ /* @__PURE__ */ v("select", {
307
309
  "aria-label": "Filter by status",
308
- value: I,
310
+ value: L,
309
311
  onChange: (e) => {
310
- L(e.target.value), V(1);
312
+ R(e.target.value), U(1);
311
313
  },
312
- className: k,
313
- children: E.map((e) => /* @__PURE__ */ S("option", {
314
+ className: A,
315
+ children: D.map((e) => /* @__PURE__ */ v("option", {
314
316
  value: e.value,
315
317
  children: e.label
316
318
  }, e.value))
317
319
  }),
318
- /* @__PURE__ */ S("select", {
320
+ /* @__PURE__ */ v("select", {
319
321
  "aria-label": "Filter by priority",
320
- value: R,
322
+ value: z,
321
323
  onChange: (e) => {
322
- z(e.target.value), V(1);
324
+ B(e.target.value), U(1);
323
325
  },
324
- className: k,
325
- children: D.map((e) => /* @__PURE__ */ S("option", {
326
+ className: A,
327
+ children: O.map((e) => /* @__PURE__ */ v("option", {
326
328
  value: e.value,
327
329
  children: e.label
328
330
  }, e.value))
329
331
  }),
330
- /* @__PURE__ */ S("select", {
332
+ /* @__PURE__ */ v("select", {
331
333
  "aria-label": "Filter by type",
332
- value: B,
334
+ value: V,
333
335
  onChange: (e) => {
334
- ue(e.target.value), V(1);
336
+ H(e.target.value), U(1);
335
337
  },
336
- className: k,
337
- children: O.map((e) => /* @__PURE__ */ S("option", {
338
+ className: A,
339
+ children: k.map((e) => /* @__PURE__ */ v("option", {
338
340
  value: e.value,
339
341
  children: e.label
340
342
  }, e.value))
341
343
  })
342
344
  ] })
343
345
  }),
344
- /* @__PURE__ */ S(r, {
345
- columns: ye,
346
- data: H,
346
+ /* @__PURE__ */ v(r, {
347
+ columns: be,
348
+ data: W,
347
349
  keyField: "id",
348
350
  emptyMessage: "No verification items found",
349
351
  emptyIllustration: "empty-search",
350
352
  emptyDescription: "Verification requests you submit will appear here so you can track their progress.",
351
353
  pageSize: 10,
352
354
  serverPagination: {
353
- page: j.page,
354
- pageSize: j.pageSize,
355
- hasNextPage: H.length >= j.pageSize,
356
- loading: U,
357
- onPageChange: j.setPage,
358
- onPageSizeChange: j.setPageSize
355
+ page: M.page,
356
+ pageSize: M.pageSize,
357
+ hasNextPage: W.length >= M.pageSize,
358
+ loading: ue,
359
+ onPageChange: M.setPage,
360
+ onPageSizeChange: M.setPageSize
359
361
  }
360
362
  })
361
363
  ] }),
362
- /* @__PURE__ */ S(te, {
363
- open: W !== null,
364
- onOpenChange: (e) => !e && X(),
365
- children: /* @__PURE__ */ S(ne, {
364
+ /* @__PURE__ */ v(S, {
365
+ open: G !== null,
366
+ onOpenChange: (e) => !e && Z(),
367
+ children: /* @__PURE__ */ v(C, {
366
368
  className: "sm:max-w-md",
367
- children: /* @__PURE__ */ C("form", {
369
+ children: /* @__PURE__ */ y("form", {
368
370
  onSubmit: he,
369
371
  children: [
370
- /* @__PURE__ */ C(ae, { children: [/* @__PURE__ */ S(oe, { children: $ ? "Approve verification" : "Reject verification" }), /* @__PURE__ */ S(re, { children: $ ? `Mark "${W?.item.entityLabel ?? ""}" as verified. You can add an optional note for the record.` : `Reject "${W?.item.entityLabel ?? ""}". Add an optional note explaining why so the submitter can respond.` })] }),
371
- /* @__PURE__ */ C("div", {
372
+ /* @__PURE__ */ y(ae, { children: [/* @__PURE__ */ v(oe, { children: $ ? "Approve verification" : "Reject verification" }), /* @__PURE__ */ v(w, { children: $ ? `Mark "${G?.item.entityLabel ?? ""}" as verified. You can add an optional note for the record.` : `Reject "${G?.item.entityLabel ?? ""}". Add an optional note explaining why so the submitter can respond.` })] }),
373
+ /* @__PURE__ */ y("div", {
372
374
  className: "space-y-3 py-2",
373
- children: [/* @__PURE__ */ S("label", {
375
+ children: [/* @__PURE__ */ v("label", {
374
376
  className: "block text-sm font-medium text-text-primary",
375
377
  htmlFor: "verification-notes",
376
378
  children: "Notes (optional)"
377
- }), /* @__PURE__ */ S("textarea", {
379
+ }), /* @__PURE__ */ v("textarea", {
378
380
  id: "verification-notes",
379
- value: K,
380
- onChange: (e) => q(e.target.value),
381
+ value: q,
382
+ onChange: (e) => J(e.target.value),
381
383
  rows: 3,
382
384
  placeholder: $ ? "Anything worth noting about this approval…" : "Reason for rejection…",
383
385
  className: "w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]"
384
386
  })]
385
387
  }),
386
- /* @__PURE__ */ C(ie, { children: [/* @__PURE__ */ S(w, {
388
+ /* @__PURE__ */ y(T, { children: [/* @__PURE__ */ v(b, {
387
389
  type: "button",
388
390
  variant: "outline",
389
- onClick: X,
390
- disabled: J,
391
+ onClick: Z,
392
+ disabled: Y,
391
393
  children: "Cancel"
392
- }), /* @__PURE__ */ S(w, {
394
+ }), /* @__PURE__ */ v(b, {
393
395
  type: "submit",
394
396
  variant: $ ? "default" : "destructive",
395
- disabled: J,
396
- children: J ? "Submitting…" : $ ? "Approve" : "Reject"
397
+ disabled: Y,
398
+ children: Y ? "Submitting…" : $ ? "Approve" : "Reject"
397
399
  })] })
398
400
  ]
399
401
  })
@@ -403,6 +405,6 @@ function j() {
403
405
  });
404
406
  }
405
407
  //#endregion
406
- export { j as VerificationPage };
408
+ export { M as VerificationPage };
407
409
 
408
410
  //# sourceMappingURL=VerificationPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"VerificationPage.js","names":[],"sources":["../../../../src/housingvista/pages/verification/VerificationPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Shield, CheckCircle, Clock, XCircle, Eye, Check, X } from 'lucide-react';\nimport {\n Button,\n EmphasisPanel,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, DataTable, StatusBadge, FilterBar } from '../../components';\nimport type { Column } from '../../components';\nimport { useVerifications, useApproveVerification, useRejectVerification } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatDate } from '../../utils/helpers';\nimport type { VerificationItem } from '../../types';\n\nfunction getStatusVariant(status: string): 'success' | 'warning' | 'error' | 'info' {\n switch (status) {\n case 'verified':\n return 'success';\n case 'in_progress':\n return 'info';\n case 'pending':\n return 'warning';\n case 'rejected':\n return 'error';\n default:\n return 'info';\n }\n}\n\nfunction getStatusLabel(status: string): string {\n return status.replace('_', ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction getEntityTypeLabel(type: string): string {\n return type.replace('_', ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction getPriorityBadge(priority: string) {\n const styles: Record<string, string> = {\n high: 'bg-status-error-bg-subtle text-status-error-text',\n medium: 'bg-status-warning-bg-subtle text-status-warning-text',\n low: 'bg-status-success-bg-subtle text-status-success-text',\n };\n return (\n <span\n className={cn(\n 'inline-flex rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n styles[priority] ?? styles.low\n )}\n >\n {priority}\n </span>\n );\n}\n\ntype DecisionMode = 'approve' | 'reject';\n\nconst STATUS_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All statuses' },\n { value: 'pending', label: 'Pending' },\n { value: 'in_progress', label: 'In Progress' },\n { value: 'verified', label: 'Verified' },\n { value: 'rejected', label: 'Rejected' },\n];\n\nconst PRIORITY_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All priorities' },\n { value: 'high', label: 'High' },\n { value: 'medium', label: 'Medium' },\n { value: 'low', label: 'Low' },\n];\n\nconst ENTITY_TYPE_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All types' },\n { value: 'property', label: 'Property' },\n { value: 'user', label: 'User' },\n { value: 'document', label: 'Document' },\n { value: 'income', label: 'Income' },\n { value: 'bank_account', label: 'Bank Account' },\n];\n\nconst SELECT_CLASS =\n 'h-9 rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n/** Trust stat card with a proportion bar (share of the total on this page). */\nfunction VerifStat({\n label,\n value,\n total,\n tone,\n icon,\n}: {\n label: string;\n value: number;\n total: number;\n tone: 'success' | 'warning' | 'error' | 'info';\n icon: React.ReactNode;\n}) {\n const pct = total > 0 ? Math.round((value / total) * 100) : 0;\n const barColor = {\n success: 'bg-status-success-text',\n warning: 'bg-status-warning-text',\n error: 'bg-status-error-text',\n info: 'bg-status-info-text',\n }[tone];\n const iconBg = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n info: 'bg-status-info-bg-subtle text-status-info-text',\n }[tone];\n return (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">{value}</span>\n <span className={cn('flex h-8 w-8 items-center justify-center rounded-lg', iconBg)}>{icon}</span>\n </div>\n <p className=\"mt-0.5 text-sm font-medium text-text-secondary\">{label}</p>\n <div className=\"mt-3 h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div className={cn('h-full rounded-full transition-all', barColor)} style={{ width: `${pct}%` }} />\n </div>\n </div>\n );\n}\n\nexport function VerificationPage() {\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('');\n const [priorityFilter, setPriorityFilter] = useState('');\n const [entityTypeFilter, setEntityTypeFilter] = useState('');\n\n const { setPage } = pagination;\n\n // Debounce the free-text search into the server filter; reset to page 1 on change.\n useEffect(() => {\n const handle = setTimeout(() => {\n setDebouncedSearch(search.trim());\n setPage(1);\n }, 300);\n return () => clearTimeout(handle);\n }, [search, setPage]);\n\n const { data: verifications, loading } = useVerifications({\n filter: {\n search: debouncedSearch || undefined,\n status: statusFilter || undefined,\n priority: priorityFilter || undefined,\n entityType: entityTypeFilter || undefined,\n },\n pagination: pagination.pagination,\n });\n const { approveVerification, loading: approving } = useApproveVerification();\n const { rejectVerification, loading: rejecting } = useRejectVerification();\n\n const [decision, setDecision] = useState<{ item: VerificationItem; mode: DecisionMode } | null>(null);\n const [notes, setNotes] = useState('');\n\n const submitting = approving || rejecting;\n\n const openDecision = (item: VerificationItem, mode: DecisionMode) => {\n setDecision({ item, mode });\n setNotes('');\n };\n\n const closeDecision = () => {\n if (submitting) return;\n setDecision(null);\n setNotes('');\n };\n\n const handleConfirm = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!decision) return;\n const trimmedNotes = notes.trim() || undefined;\n try {\n if (decision.mode === 'approve') {\n await approveVerification(decision.item.id, trimmedNotes);\n notify.success('Verification approved', decision.item.entityLabel);\n } else {\n await rejectVerification(decision.item.id, trimmedNotes);\n notify.success('Verification rejected', decision.item.entityLabel);\n }\n setDecision(null);\n setNotes('');\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Please try again.';\n notify.error(\n decision.mode === 'approve' ? 'Could not approve verification' : 'Could not reject verification',\n message\n );\n }\n };\n\n const verified = verifications.filter((v) => v.status === 'verified').length;\n const pending = verifications.filter((v) => v.status === 'pending').length;\n const inProgress = verifications.filter((v) => v.status === 'in_progress').length;\n const rejected = verifications.filter((v) => v.status === 'rejected').length;\n const total = verifications.length;\n\n const columns: Column<VerificationItem>[] = [\n {\n key: 'entityLabel',\n header: 'Item',\n render: (item) => (\n <div>\n <p className=\"font-medium text-text-primary\">{item.entityLabel}</p>\n {item.notes && <p className=\"mt-0.5 text-xs text-text-secondary line-clamp-1\">{item.notes}</p>}\n </div>\n ),\n },\n {\n key: 'entityType',\n header: 'Type',\n render: (item) => (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary capitalize\">\n {getEntityTypeLabel(item.entityType)}\n </span>\n ),\n },\n {\n key: 'priority',\n header: 'Priority',\n render: (item) => getPriorityBadge(item.priority),\n },\n {\n key: 'submittedDate',\n header: 'Submitted',\n render: (item) => <span className=\"text-sm text-text-secondary\">{formatDate(item.submittedDate)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (item) => <StatusBadge label={getStatusLabel(item.status)} variant={getStatusVariant(item.status)} dot />,\n },\n {\n key: 'actions',\n header: 'Action',\n sortable: false,\n render: (item) => {\n const decidable = item.status === 'pending' || item.status === 'in_progress';\n return (\n <div className=\"flex items-center gap-1.5\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`../verification/${item.id}`);\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Eye className=\"h-3 w-3\" />\n View\n </button>\n {decidable && (\n <>\n <button\n onClick={(e) => {\n e.stopPropagation();\n openDecision(item, 'approve');\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-status-success-border bg-status-success-bg-subtle px-2.5 py-1 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle/70\"\n >\n <Check className=\"h-3 w-3\" />\n Approve\n </button>\n <button\n onClick={(e) => {\n e.stopPropagation();\n openDecision(item, 'reject');\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-status-error-border bg-status-error-bg-subtle px-2.5 py-1 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle/70\"\n >\n <X className=\"h-3 w-3\" />\n Reject\n </button>\n </>\n )}\n </div>\n );\n },\n },\n ];\n\n const isApprove = decision?.mode === 'approve';\n\n return (\n <PageLayout\n title=\"Verification Center\"\n description=\"Track and manage all your verification requests\"\n purpose=\"Submit and monitor identity, ownership, and document checks that build trust in your listings and deals. Use this page to see what is verified, what is still pending, and what was rejected so you can act before it blocks a transaction.\"\n actions={\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-3 py-1.5 text-xs font-medium text-status-success-text\">\n <Shield className=\"h-3.5 w-3.5\" />\n Trust &amp; Safety\n </span>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <VerifStat\n label=\"Verified\"\n value={verified}\n total={total}\n tone=\"success\"\n icon={<CheckCircle className=\"h-4 w-4\" />}\n />\n <VerifStat\n label=\"Pending\"\n value={pending + inProgress}\n total={total}\n tone=\"warning\"\n icon={<Clock className=\"h-4 w-4\" />}\n />\n <VerifStat\n label=\"Rejected\"\n value={rejected}\n total={total}\n tone=\"error\"\n icon={<XCircle className=\"h-4 w-4\" />}\n />\n <VerifStat label=\"Total\" value={total} total={total} tone=\"info\" icon={<Shield className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n {/* Verification Table */}\n <div>\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Verification Items</h2>\n <FilterBar\n className=\"mb-4\"\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder=\"Search verification items...\"\n filters={\n <>\n <select\n aria-label=\"Filter by status\"\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Filter by priority\"\n value={priorityFilter}\n onChange={(e) => {\n setPriorityFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {PRIORITY_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Filter by type\"\n value={entityTypeFilter}\n onChange={(e) => {\n setEntityTypeFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {ENTITY_TYPE_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </>\n }\n />\n <DataTable<VerificationItem>\n columns={columns}\n data={verifications}\n keyField=\"id\"\n emptyMessage=\"No verification items found\"\n emptyIllustration=\"empty-search\"\n emptyDescription=\"Verification requests you submit will appear here so you can track their progress.\"\n pageSize={10}\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: verifications.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n\n {/* Approve / Reject decision dialog */}\n <ResponsiveDialog open={decision !== null} onOpenChange={(open) => !open && closeDecision()}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleConfirm}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {isApprove ? 'Approve verification' : 'Reject verification'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {isApprove\n ? `Mark \"${decision?.item.entityLabel ?? ''}\" as verified. You can add an optional note for the record.`\n : `Reject \"${decision?.item.entityLabel ?? ''}\". Add an optional note explaining why so the submitter can respond.`}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <label className=\"block text-sm font-medium text-text-primary\" htmlFor=\"verification-notes\">\n Notes (optional)\n </label>\n <textarea\n id=\"verification-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder={isApprove ? 'Anything worth noting about this approval…' : 'Reason for rejection…'}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={closeDecision} disabled={submitting}>\n Cancel\n </Button>\n <Button type=\"submit\" variant={isApprove ? 'default' : 'destructive'} disabled={submitting}>\n {submitting ? 'Submitting…' : isApprove ? 'Approve' : 'Reject'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"VerificationPage.js","names":[],"sources":["../../../../src/housingvista/pages/verification/VerificationPage.tsx"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Shield, CheckCircle, Clock, XCircle, Eye, Check, X } from 'lucide-react';\nimport {\n Button,\n EmphasisPanel,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, DataTable, StatusBadge, FilterBar } from '../../components';\nimport type { Column } from '../../components';\nimport { useVerifications, useApproveVerification, useRejectVerification } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatDate } from '../../utils/helpers';\nimport type { VerificationItem } from '../../types';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nfunction getStatusVariant(status: string): 'success' | 'warning' | 'error' | 'info' {\n switch (status) {\n case 'verified':\n return 'success';\n case 'in_progress':\n return 'info';\n case 'pending':\n return 'warning';\n case 'rejected':\n return 'error';\n default:\n return 'info';\n }\n}\n\nfunction getStatusLabel(status: string): string {\n return status.replace('_', ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction getEntityTypeLabel(type: string): string {\n return type.replace('_', ' ').replace(/\\b\\w/g, (c) => c.toUpperCase());\n}\n\nfunction getPriorityBadge(priority: string) {\n const styles: Record<string, string> = {\n high: 'bg-status-error-bg-subtle text-status-error-text',\n medium: 'bg-status-warning-bg-subtle text-status-warning-text',\n low: 'bg-status-success-bg-subtle text-status-success-text',\n };\n return (\n <span\n className={cn(\n 'inline-flex rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n styles[priority] ?? styles.low\n )}\n >\n {priority}\n </span>\n );\n}\n\ntype DecisionMode = 'approve' | 'reject';\n\nconst STATUS_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All statuses' },\n { value: 'pending', label: 'Pending' },\n { value: 'in_progress', label: 'In Progress' },\n { value: 'verified', label: 'Verified' },\n { value: 'rejected', label: 'Rejected' },\n];\n\nconst PRIORITY_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All priorities' },\n { value: 'high', label: 'High' },\n { value: 'medium', label: 'Medium' },\n { value: 'low', label: 'Low' },\n];\n\nconst ENTITY_TYPE_OPTIONS: { value: string; label: string }[] = [\n { value: '', label: 'All types' },\n { value: 'property', label: 'Property' },\n { value: 'user', label: 'User' },\n { value: 'document', label: 'Document' },\n { value: 'income', label: 'Income' },\n { value: 'bank_account', label: 'Bank Account' },\n];\n\nconst SELECT_CLASS =\n 'h-9 rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n/** Trust stat card with a proportion bar (share of the total on this page). */\nfunction VerifStat({\n label,\n value,\n total,\n tone,\n icon,\n}: {\n label: string;\n value: number;\n total: number;\n tone: 'success' | 'warning' | 'error' | 'info';\n icon: React.ReactNode;\n}) {\n const pct = total > 0 ? Math.round((value / total) * 100) : 0;\n const barColor = {\n success: 'bg-status-success-text',\n warning: 'bg-status-warning-text',\n error: 'bg-status-error-text',\n info: 'bg-status-info-text',\n }[tone];\n const iconBg = {\n success: 'bg-status-success-bg-subtle text-status-success-text',\n warning: 'bg-status-warning-bg-subtle text-status-warning-text',\n error: 'bg-status-error-bg-subtle text-status-error-text',\n info: 'bg-status-info-bg-subtle text-status-info-text',\n }[tone];\n return (\n <div className=\"rounded-card border border-border-seam bg-bg-surface p-4 shadow-elevation-1\">\n <div className=\"flex items-center justify-between\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">{value}</span>\n <span className={cn('flex h-8 w-8 items-center justify-center rounded-lg', iconBg)}>{icon}</span>\n </div>\n <p className=\"mt-0.5 text-sm font-medium text-text-secondary\">{label}</p>\n <div className=\"mt-3 h-1.5 w-full overflow-hidden rounded-full bg-bg-sunken\">\n <div className={cn('h-full rounded-full transition-all', barColor)} style={{ width: `${pct}%` }} />\n </div>\n </div>\n );\n}\n\nexport function VerificationPage() {\n useTrackPageView('housingvista.verification.viewed');\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [statusFilter, setStatusFilter] = useState('');\n const [priorityFilter, setPriorityFilter] = useState('');\n const [entityTypeFilter, setEntityTypeFilter] = useState('');\n\n const { setPage } = pagination;\n\n // Debounce the free-text search into the server filter; reset to page 1 on change.\n useEffect(() => {\n const handle = setTimeout(() => {\n setDebouncedSearch(search.trim());\n setPage(1);\n }, 300);\n return () => clearTimeout(handle);\n }, [search, setPage]);\n\n const { data: verifications, loading } = useVerifications({\n filter: {\n search: debouncedSearch || undefined,\n status: statusFilter || undefined,\n priority: priorityFilter || undefined,\n entityType: entityTypeFilter || undefined,\n },\n pagination: pagination.pagination,\n });\n const { approveVerification, loading: approving } = useApproveVerification();\n const { rejectVerification, loading: rejecting } = useRejectVerification();\n\n const [decision, setDecision] = useState<{ item: VerificationItem; mode: DecisionMode } | null>(null);\n const [notes, setNotes] = useState('');\n\n const submitting = approving || rejecting;\n\n const openDecision = (item: VerificationItem, mode: DecisionMode) => {\n setDecision({ item, mode });\n setNotes('');\n };\n\n const closeDecision = () => {\n if (submitting) return;\n setDecision(null);\n setNotes('');\n };\n\n const handleConfirm = async (e: React.FormEvent) => {\n e.preventDefault();\n if (!decision) return;\n const trimmedNotes = notes.trim() || undefined;\n try {\n if (decision.mode === 'approve') {\n await approveVerification(decision.item.id, trimmedNotes);\n notify.success('Verification approved', decision.item.entityLabel);\n } else {\n await rejectVerification(decision.item.id, trimmedNotes);\n notify.success('Verification rejected', decision.item.entityLabel);\n }\n setDecision(null);\n setNotes('');\n } catch (err) {\n const message = err instanceof Error ? err.message : 'Please try again.';\n notify.error(\n decision.mode === 'approve' ? 'Could not approve verification' : 'Could not reject verification',\n message\n );\n }\n };\n\n const verified = verifications.filter((v) => v.status === 'verified').length;\n const pending = verifications.filter((v) => v.status === 'pending').length;\n const inProgress = verifications.filter((v) => v.status === 'in_progress').length;\n const rejected = verifications.filter((v) => v.status === 'rejected').length;\n const total = verifications.length;\n\n const columns: Column<VerificationItem>[] = [\n {\n key: 'entityLabel',\n header: 'Item',\n render: (item) => (\n <div>\n <p className=\"font-medium text-text-primary\">{item.entityLabel}</p>\n {item.notes && <p className=\"mt-0.5 text-xs text-text-secondary line-clamp-1\">{item.notes}</p>}\n </div>\n ),\n },\n {\n key: 'entityType',\n header: 'Type',\n render: (item) => (\n <span className=\"inline-flex items-center gap-1 text-xs text-text-secondary capitalize\">\n {getEntityTypeLabel(item.entityType)}\n </span>\n ),\n },\n {\n key: 'priority',\n header: 'Priority',\n render: (item) => getPriorityBadge(item.priority),\n },\n {\n key: 'submittedDate',\n header: 'Submitted',\n render: (item) => <span className=\"text-sm text-text-secondary\">{formatDate(item.submittedDate)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (item) => <StatusBadge label={getStatusLabel(item.status)} variant={getStatusVariant(item.status)} dot />,\n },\n {\n key: 'actions',\n header: 'Action',\n sortable: false,\n render: (item) => {\n const decidable = item.status === 'pending' || item.status === 'in_progress';\n return (\n <div className=\"flex items-center gap-1.5\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`../verification/${item.id}`);\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-2.5 py-1 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Eye className=\"h-3 w-3\" />\n View\n </button>\n {decidable && (\n <>\n <button\n onClick={(e) => {\n e.stopPropagation();\n openDecision(item, 'approve');\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-status-success-border bg-status-success-bg-subtle px-2.5 py-1 text-xs font-medium text-status-success-text transition-colors hover:bg-status-success-bg-subtle/70\"\n >\n <Check className=\"h-3 w-3\" />\n Approve\n </button>\n <button\n onClick={(e) => {\n e.stopPropagation();\n openDecision(item, 'reject');\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-status-error-border bg-status-error-bg-subtle px-2.5 py-1 text-xs font-medium text-status-error-text transition-colors hover:bg-status-error-bg-subtle/70\"\n >\n <X className=\"h-3 w-3\" />\n Reject\n </button>\n </>\n )}\n </div>\n );\n },\n },\n ];\n\n const isApprove = decision?.mode === 'approve';\n\n return (\n <PageLayout\n title=\"Verification Center\"\n description=\"Track and manage all your verification requests\"\n purpose=\"Submit and monitor identity, ownership, and document checks that build trust in your listings and deals. Use this page to see what is verified, what is still pending, and what was rejected so you can act before it blocks a transaction.\"\n actions={\n <span className=\"inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-3 py-1.5 text-xs font-medium text-status-success-text\">\n <Shield className=\"h-3.5 w-3.5\" />\n Trust &amp; Safety\n </span>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <VerifStat\n label=\"Verified\"\n value={verified}\n total={total}\n tone=\"success\"\n icon={<CheckCircle className=\"h-4 w-4\" />}\n />\n <VerifStat\n label=\"Pending\"\n value={pending + inProgress}\n total={total}\n tone=\"warning\"\n icon={<Clock className=\"h-4 w-4\" />}\n />\n <VerifStat\n label=\"Rejected\"\n value={rejected}\n total={total}\n tone=\"error\"\n icon={<XCircle className=\"h-4 w-4\" />}\n />\n <VerifStat label=\"Total\" value={total} total={total} tone=\"info\" icon={<Shield className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n {/* Verification Table */}\n <div>\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Verification Items</h2>\n <FilterBar\n className=\"mb-4\"\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder=\"Search verification items...\"\n filters={\n <>\n <select\n aria-label=\"Filter by status\"\n value={statusFilter}\n onChange={(e) => {\n setStatusFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {STATUS_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Filter by priority\"\n value={priorityFilter}\n onChange={(e) => {\n setPriorityFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {PRIORITY_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n <select\n aria-label=\"Filter by type\"\n value={entityTypeFilter}\n onChange={(e) => {\n setEntityTypeFilter(e.target.value);\n setPage(1);\n }}\n className={SELECT_CLASS}\n >\n {ENTITY_TYPE_OPTIONS.map((o) => (\n <option key={o.value} value={o.value}>\n {o.label}\n </option>\n ))}\n </select>\n </>\n }\n />\n <DataTable<VerificationItem>\n columns={columns}\n data={verifications}\n keyField=\"id\"\n emptyMessage=\"No verification items found\"\n emptyIllustration=\"empty-search\"\n emptyDescription=\"Verification requests you submit will appear here so you can track their progress.\"\n pageSize={10}\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: verifications.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n\n {/* Approve / Reject decision dialog */}\n <ResponsiveDialog open={decision !== null} onOpenChange={(open) => !open && closeDecision()}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleConfirm}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {isApprove ? 'Approve verification' : 'Reject verification'}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {isApprove\n ? `Mark \"${decision?.item.entityLabel ?? ''}\" as verified. You can add an optional note for the record.`\n : `Reject \"${decision?.item.entityLabel ?? ''}\". Add an optional note explaining why so the submitter can respond.`}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <label className=\"block text-sm font-medium text-text-primary\" htmlFor=\"verification-notes\">\n Notes (optional)\n </label>\n <textarea\n id=\"verification-notes\"\n value={notes}\n onChange={(e) => setNotes(e.target.value)}\n rows={3}\n placeholder={isApprove ? 'Anything worth noting about this approval…' : 'Reason for rejection…'}\n className=\"w-full rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={closeDecision} disabled={submitting}>\n Cancel\n </Button>\n <Button type=\"submit\" variant={isApprove ? 'default' : 'destructive'} disabled={submitting}>\n {submitting ? 'Submitting…' : isApprove ? 'Approve' : 'Reject'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ViewingsPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/viewings/ViewingsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAqEH,wBAAgB,YAAY,gCAuT3B"}
1
+ {"version":3,"file":"ViewingsPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/viewings/ViewingsPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAsEH,wBAAgB,YAAY,gCAwT3B"}