@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,16 +3,17 @@ import { PageLayout as n } from "../../components/PageLayout.js";
3
3
  import { EmptyState as r } from "../../components/EmptyState.js";
4
4
  import { FilterBar as i } from "../../components/FilterBar.js";
5
5
  import { LoadingSkeleton as a } from "../../components/LoadingSkeleton.js";
6
- import { useLegalServices as o } from "../../hooks/index.js";
6
+ import { useTrackPageView as o } from "../../hooks/useHousingVistaAnalytics.js";
7
+ import { useLegalServices as s } from "../../hooks/index.js";
7
8
  import "../../components/index.js";
8
- import { useServerPagination as s } from "../../hooks/useServerPagination.js";
9
- import { useEffect as c, useMemo as l, useState as u } from "react";
10
- import { BookOpen as d, ClipboardCheck as f, Clock as p, FileText as m, Gavel as h, Scale as g, Search as _, Shield as v, Star as y } from "lucide-react";
11
- import { useNavigate as b } from "react-router-dom";
12
- import { Fragment as x, jsx as S, jsxs as C } from "react/jsx-runtime";
13
- import { EmphasisPanel as w, NextSteps as T, Pagination as E } from "@burdenoff/fe-libs/ui";
9
+ import { useServerPagination as c } from "../../hooks/useServerPagination.js";
10
+ import { useEffect as l, useMemo as u, useState as d } from "react";
11
+ import { BookOpen as f, ClipboardCheck as p, Clock as m, FileText as h, Gavel as g, Scale as _, Search as v, Shield as y, Star as b } from "lucide-react";
12
+ import { useNavigate as x } from "react-router-dom";
13
+ import { Fragment as S, jsx as C, jsxs as w } from "react/jsx-runtime";
14
+ import { EmphasisPanel as T, NextSteps as E, Pagination as D } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/housingvista/pages/legal/LegalPage.tsx
15
- var D = 9, O = [
16
+ var O = 9, k = [
16
17
  {
17
18
  value: "all",
18
19
  label: "All"
@@ -38,17 +39,17 @@ var D = 9, O = [
38
39
  label: "Document Review"
39
40
  }
40
41
  ];
41
- function k(e) {
42
+ function A(e) {
42
43
  switch (e) {
43
- case "title_search": return /* @__PURE__ */ S(_, { className: "h-4 w-4" });
44
- case "lease_review": return /* @__PURE__ */ S(m, { className: "h-4 w-4" });
45
- case "dispute_resolution": return /* @__PURE__ */ S(h, { className: "h-4 w-4" });
46
- case "registration": return /* @__PURE__ */ S(f, { className: "h-4 w-4" });
47
- case "compliance": return /* @__PURE__ */ S(d, { className: "h-4 w-4" });
48
- default: return /* @__PURE__ */ S(g, { className: "h-4 w-4" });
44
+ case "title_search": return /* @__PURE__ */ C(v, { className: "h-4 w-4" });
45
+ case "lease_review": return /* @__PURE__ */ C(h, { className: "h-4 w-4" });
46
+ case "dispute_resolution": return /* @__PURE__ */ C(g, { className: "h-4 w-4" });
47
+ case "registration": return /* @__PURE__ */ C(p, { className: "h-4 w-4" });
48
+ case "compliance": return /* @__PURE__ */ C(f, { className: "h-4 w-4" });
49
+ default: return /* @__PURE__ */ C(_, { className: "h-4 w-4" });
49
50
  }
50
51
  }
51
- function A(e) {
52
+ function j(e) {
52
53
  switch (e) {
53
54
  case "available": return "bg-status-success-bg-subtle text-status-success-text";
54
55
  case "busy": return "bg-status-warning-bg-subtle text-status-warning-text";
@@ -56,95 +57,95 @@ function A(e) {
56
57
  default: return "bg-bg-sunken text-text-secondary";
57
58
  }
58
59
  }
59
- function j({ rating: t }) {
60
- return /* @__PURE__ */ S("div", {
60
+ function M({ rating: t }) {
61
+ return /* @__PURE__ */ C("div", {
61
62
  className: "flex items-center gap-0.5 text-status-warning-text",
62
- children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ S(y, { className: e("h-3 w-3", r < Math.floor(t) ? "fill-current" : "fill-none text-text-secondary/30") }, r))
63
+ children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ C(b, { className: e("h-3 w-3", r < Math.floor(t) ? "fill-current" : "fill-none text-text-secondary/30") }, r))
63
64
  });
64
65
  }
65
- function M({ service: n }) {
66
- let r = b(), [i, a] = u(!1);
67
- return /* @__PURE__ */ C("div", {
66
+ function N({ service: n }) {
67
+ let r = x(), [i, a] = d(!1);
68
+ return /* @__PURE__ */ w("div", {
68
69
  className: "flex flex-col rounded-card border border-border-seam bg-bg-surface p-5 shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2",
69
70
  children: [
70
- /* @__PURE__ */ C("div", {
71
+ /* @__PURE__ */ w("div", {
71
72
  className: "mb-3 flex items-start justify-between gap-3",
72
- children: [/* @__PURE__ */ C("div", {
73
+ children: [/* @__PURE__ */ w("div", {
73
74
  className: "flex items-start gap-3",
74
- children: [/* @__PURE__ */ S("div", {
75
+ children: [/* @__PURE__ */ C("div", {
75
76
  className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-accent-blue-subtle text-accent-blue",
76
- children: k(n.category)
77
- }), /* @__PURE__ */ C("div", {
77
+ children: A(n.category)
78
+ }), /* @__PURE__ */ w("div", {
78
79
  className: "min-w-0",
79
80
  children: [
80
- /* @__PURE__ */ S("h3", {
81
+ /* @__PURE__ */ C("h3", {
81
82
  className: "truncate text-sm font-semibold text-text-primary",
82
83
  children: n.title
83
84
  }),
84
- /* @__PURE__ */ S("p", {
85
+ /* @__PURE__ */ C("p", {
85
86
  className: "truncate text-xs text-text-secondary",
86
87
  children: n.providerName
87
88
  }),
88
- /* @__PURE__ */ C("div", {
89
+ /* @__PURE__ */ w("div", {
89
90
  className: "mt-1 flex items-center gap-1.5",
90
- children: [/* @__PURE__ */ S(j, { rating: n.providerRating }), /* @__PURE__ */ S("span", {
91
+ children: [/* @__PURE__ */ C(M, { rating: n.providerRating }), /* @__PURE__ */ C("span", {
91
92
  className: "text-xs font-medium text-text-primary",
92
93
  children: n.providerRating
93
94
  })]
94
95
  })
95
96
  ]
96
97
  })]
97
- }), /* @__PURE__ */ S("span", {
98
- className: e("inline-flex shrink-0 rounded-full px-2 py-0.5 text-xs font-medium capitalize", A(n.status)),
98
+ }), /* @__PURE__ */ C("span", {
99
+ className: e("inline-flex shrink-0 rounded-full px-2 py-0.5 text-xs font-medium capitalize", j(n.status)),
99
100
  children: n.status
100
101
  })]
101
102
  }),
102
- /* @__PURE__ */ S("p", {
103
+ /* @__PURE__ */ C("p", {
103
104
  className: "mb-4 text-xs text-text-secondary line-clamp-2",
104
105
  children: n.description
105
106
  }),
106
- /* @__PURE__ */ C("div", {
107
+ /* @__PURE__ */ w("div", {
107
108
  className: "mb-4 grid grid-cols-2 gap-3",
108
- children: [/* @__PURE__ */ C("div", {
109
+ children: [/* @__PURE__ */ w("div", {
109
110
  className: "rounded-md bg-bg-sunken/50 p-2.5",
110
- children: [/* @__PURE__ */ C("p", {
111
+ children: [/* @__PURE__ */ w("p", {
111
112
  className: "flex items-center gap-1 text-xs text-text-secondary",
112
- children: [/* @__PURE__ */ S(p, { className: "h-3 w-3" }), "Est. Duration"]
113
- }), /* @__PURE__ */ S("p", {
113
+ children: [/* @__PURE__ */ C(m, { className: "h-3 w-3" }), "Est. Duration"]
114
+ }), /* @__PURE__ */ C("p", {
114
115
  className: "mt-0.5 text-sm font-semibold text-text-primary",
115
116
  children: n.estimatedDuration
116
117
  })]
117
- }), /* @__PURE__ */ C("div", {
118
+ }), /* @__PURE__ */ w("div", {
118
119
  className: "rounded-md bg-bg-sunken/50 p-2.5",
119
- children: [/* @__PURE__ */ S("p", {
120
+ children: [/* @__PURE__ */ C("p", {
120
121
  className: "text-xs text-text-secondary",
121
122
  children: "Price Range"
122
- }), /* @__PURE__ */ S("p", {
123
+ }), /* @__PURE__ */ C("p", {
123
124
  className: "mt-0.5 text-sm font-semibold text-text-primary",
124
125
  children: n.priceRange
125
126
  })]
126
127
  })]
127
128
  }),
128
- /* @__PURE__ */ S("div", {
129
+ /* @__PURE__ */ C("div", {
129
130
  className: "mb-3 text-xs",
130
- children: n.consultationFee > 0 ? /* @__PURE__ */ C("span", {
131
+ children: n.consultationFee > 0 ? /* @__PURE__ */ w("span", {
131
132
  className: "text-text-secondary",
132
133
  children: [
133
134
  "Consultation:",
134
135
  " ",
135
- /* @__PURE__ */ S("span", {
136
+ /* @__PURE__ */ C("span", {
136
137
  className: "font-medium text-text-primary",
137
138
  children: t(n.consultationFee)
138
139
  })
139
140
  ]
140
- }) : /* @__PURE__ */ S("span", {
141
+ }) : /* @__PURE__ */ C("span", {
141
142
  className: "inline-flex items-center gap-1 font-medium text-status-success-text",
142
143
  children: "Free consultation"
143
144
  })
144
145
  }),
145
- n.documentsRequired.length > 0 && /* @__PURE__ */ C("div", {
146
+ n.documentsRequired.length > 0 && /* @__PURE__ */ w("div", {
146
147
  className: "mb-4",
147
- children: [/* @__PURE__ */ C("button", {
148
+ children: [/* @__PURE__ */ w("button", {
148
149
  onClick: () => a(!i),
149
150
  "aria-expanded": i,
150
151
  className: "text-xs font-medium text-accent-blue hover:underline",
@@ -154,15 +155,15 @@ function M({ service: n }) {
154
155
  n.documentsRequired.length,
155
156
  ")"
156
157
  ]
157
- }), i && /* @__PURE__ */ S("ul", {
158
+ }), i && /* @__PURE__ */ C("ul", {
158
159
  className: "mt-1.5 space-y-1",
159
- children: n.documentsRequired.map((e, t) => /* @__PURE__ */ C("li", {
160
+ children: n.documentsRequired.map((e, t) => /* @__PURE__ */ w("li", {
160
161
  className: "flex items-center gap-1.5 text-xs text-text-secondary",
161
- children: [/* @__PURE__ */ S("span", { className: "h-1 w-1 shrink-0 rounded-full bg-text-secondary/50" }), e]
162
+ children: [/* @__PURE__ */ C("span", { className: "h-1 w-1 shrink-0 rounded-full bg-text-secondary/50" }), e]
162
163
  }, t))
163
164
  })]
164
165
  }),
165
- /* @__PURE__ */ S("button", {
166
+ /* @__PURE__ */ C("button", {
166
167
  onClick: () => r(`../legal/${n.id}`),
167
168
  disabled: n.status === "unavailable",
168
169
  className: e("mt-auto w-full rounded-md px-4 py-2 text-xs font-medium transition-colors", n.status === "unavailable" ? "cursor-not-allowed bg-bg-sunken text-text-secondary" : "bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover"),
@@ -171,84 +172,85 @@ function M({ service: n }) {
171
172
  ]
172
173
  });
173
174
  }
174
- function N() {
175
- let [t, d] = u("all"), [f, p] = u(""), [m, h] = u(""), _ = s(D), { setPage: y } = _;
176
- c(() => {
177
- let e = setTimeout(() => h(f), 300);
175
+ function P() {
176
+ o("housingvista.legal.viewed");
177
+ let [t, f] = d("all"), [p, m] = d(""), [h, g] = d(""), v = c(O), { setPage: b } = v;
178
+ l(() => {
179
+ let e = setTimeout(() => g(p), 300);
178
180
  return () => clearTimeout(e);
179
- }, [f]);
180
- let b = l(() => {
181
+ }, [p]);
182
+ let x = u(() => {
181
183
  let e = {};
182
- return m.trim() && (e.search = m.trim()), t !== "all" && (e.category = t), Object.keys(e).length > 0 ? e : void 0;
183
- }, [m, t]);
184
- c(() => {
185
- y(1);
186
- }, [b, y]);
187
- let { data: k, loading: A } = o({
188
- filter: b,
189
- pagination: _.pagination
190
- }), j = k.length >= _.pageSize;
191
- return /* @__PURE__ */ C(n, {
184
+ return h.trim() && (e.search = h.trim()), t !== "all" && (e.category = t), Object.keys(e).length > 0 ? e : void 0;
185
+ }, [h, t]);
186
+ l(() => {
187
+ b(1);
188
+ }, [x, b]);
189
+ let { data: A, loading: j } = s({
190
+ filter: x,
191
+ pagination: v.pagination
192
+ }), M = A.length >= v.pageSize;
193
+ return /* @__PURE__ */ w(n, {
192
194
  title: "Legal Services",
193
195
  description: "Professional legal solutions for property transactions and documentation",
194
196
  purpose: "Connect with verified property lawyers for the legal work behind every deal — title verification, rent agreements, registration, dispute advisory, and document review. Browse by category, compare ratings and fees, and book a consultation.",
195
- actions: /* @__PURE__ */ C("span", {
197
+ actions: /* @__PURE__ */ w("span", {
196
198
  className: "inline-flex items-center gap-1 text-xs text-status-success-text",
197
- children: [/* @__PURE__ */ S(v, { className: "h-3.5 w-3.5" }), "Legally Compliant"]
199
+ children: [/* @__PURE__ */ C(y, { className: "h-3.5 w-3.5" }), "Legally Compliant"]
198
200
  }),
199
201
  children: [
200
- /* @__PURE__ */ S(w, {
202
+ /* @__PURE__ */ C(T, {
201
203
  className: "flex flex-wrap items-center gap-2 p-3",
202
- children: O.map((n) => /* @__PURE__ */ S("button", {
203
- onClick: () => d(n.value),
204
+ children: k.map((n) => /* @__PURE__ */ C("button", {
205
+ onClick: () => f(n.value),
204
206
  className: e("rounded-full px-4 py-1.5 text-sm font-medium transition-colors", t === n.value ? "bg-action-primary-bg text-action-primary-text" : "border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary"),
205
207
  children: n.label
206
208
  }, n.value))
207
209
  }),
208
- /* @__PURE__ */ S(i, {
209
- searchValue: f,
210
- onSearchChange: p,
210
+ /* @__PURE__ */ C(i, {
211
+ searchValue: p,
212
+ onSearchChange: m,
211
213
  searchPlaceholder: "Search legal services..."
212
214
  }),
213
- /* @__PURE__ */ S(T, {
215
+ /* @__PURE__ */ C(E, {
214
216
  storageKey: "housingvista-legal",
215
217
  steps: [
216
218
  {
217
219
  id: "verify-title",
218
220
  label: "Verify a property title",
219
221
  description: "The first legal check before any purchase — find a title-search expert.",
220
- onClick: () => d("title_search")
222
+ onClick: () => f("title_search")
221
223
  },
222
224
  {
223
225
  id: "rent-agreement",
224
226
  label: "Draft or review a rent agreement",
225
227
  description: "Get a lawyer to prepare or vet your lease paperwork.",
226
- onClick: () => d("lease_review")
228
+ onClick: () => f("lease_review")
227
229
  },
228
230
  {
229
231
  id: "registration",
230
232
  label: "Handle property registration",
231
233
  description: "Find help to register a deal with the authorities.",
232
- onClick: () => d("registration")
234
+ onClick: () => f("registration")
233
235
  }
234
236
  ]
235
237
  }),
236
- A ? /* @__PURE__ */ S(a, {
238
+ j ? /* @__PURE__ */ C(a, {
237
239
  variant: "card",
238
240
  count: 6
239
- }) : k.length > 0 ? /* @__PURE__ */ C(x, { children: [/* @__PURE__ */ S("div", {
241
+ }) : A.length > 0 ? /* @__PURE__ */ w(S, { children: [/* @__PURE__ */ C("div", {
240
242
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
241
- children: k.map((e) => /* @__PURE__ */ S(M, { service: e }, e.id))
242
- }), /* @__PURE__ */ S(E, {
243
- page: _.page,
244
- pageSize: _.pageSize,
245
- hasNextPage: j,
246
- hasPreviousPage: _.page > 1,
247
- onPageChange: _.setPage,
248
- onPageSizeChange: _.setPageSize
249
- })] }) : /* @__PURE__ */ S(r, {
243
+ children: A.map((e) => /* @__PURE__ */ C(N, { service: e }, e.id))
244
+ }), /* @__PURE__ */ C(D, {
245
+ page: v.page,
246
+ pageSize: v.pageSize,
247
+ hasNextPage: M,
248
+ hasPreviousPage: v.page > 1,
249
+ onPageChange: v.setPage,
250
+ onPageSizeChange: v.setPageSize
251
+ })] }) : /* @__PURE__ */ C(r, {
250
252
  illustration: "empty-search",
251
- icon: /* @__PURE__ */ S(g, { className: "h-12 w-12" }),
253
+ icon: /* @__PURE__ */ C(_, { className: "h-12 w-12" }),
252
254
  title: "No legal services found",
253
255
  description: "Try adjusting your search or category filter."
254
256
  })
@@ -256,6 +258,6 @@ function N() {
256
258
  });
257
259
  }
258
260
  //#endregion
259
- export { N as LegalPage };
261
+ export { P as LegalPage };
260
262
 
261
263
  //# sourceMappingURL=LegalPage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"LegalPage.js","names":[],"sources":["../../../../src/housingvista/pages/legal/LegalPage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Scale,\n Star,\n Clock,\n FileText,\n Search as SearchIcon,\n Shield,\n Gavel,\n BookOpen,\n ClipboardCheck,\n} from 'lucide-react';\nimport { EmphasisPanel, NextSteps, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, EmptyState, LoadingSkeleton } from '../../components';\nimport { useLegalServices, type LegalServiceFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn, formatCurrency } from '../../utils/helpers';\nimport type { LegalService } from '../../types';\n\nconst PAGE_SIZE = 9;\n\ntype CategoryTab = 'all' | 'title_search' | 'lease_review' | 'dispute_resolution' | 'registration' | 'compliance';\n\nconst categoryTabs: { value: CategoryTab; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'title_search', label: 'Title Verification' },\n { value: 'lease_review', label: 'Rent Agreement' },\n { value: 'dispute_resolution', label: 'Advisory' },\n { value: 'registration', label: 'Registration' },\n { value: 'compliance', label: 'Document Review' },\n];\n\nfunction getCategoryIcon(category: string) {\n switch (category) {\n case 'title_search':\n return <SearchIcon className=\"h-4 w-4\" />;\n case 'lease_review':\n return <FileText className=\"h-4 w-4\" />;\n case 'dispute_resolution':\n return <Gavel className=\"h-4 w-4\" />;\n case 'registration':\n return <ClipboardCheck className=\"h-4 w-4\" />;\n case 'compliance':\n return <BookOpen className=\"h-4 w-4\" />;\n default:\n return <Scale className=\"h-4 w-4\" />;\n }\n}\n\nfunction getStatusStyles(status: string) {\n switch (status) {\n case 'available':\n return 'bg-status-success-bg-subtle text-status-success-text';\n case 'busy':\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n case 'unavailable':\n return 'bg-status-error-bg-subtle text-status-error-text';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5 text-status-warning-text\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn('h-3 w-3', i < Math.floor(rating) ? 'fill-current' : 'fill-none text-text-secondary/30')}\n />\n ))}\n </div>\n );\n}\n\nfunction LegalServiceCard({ service }: { service: LegalService }) {\n const navigate = useNavigate();\n const [showDocs, setShowDocs] = useState(false);\n\n return (\n <div className=\"flex flex-col rounded-card border border-border-seam bg-bg-surface p-5 shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2\">\n {/* Header */}\n <div className=\"mb-3 flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-accent-blue-subtle text-accent-blue\">\n {getCategoryIcon(service.category)}\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{service.title}</h3>\n <p className=\"truncate text-xs text-text-secondary\">{service.providerName}</p>\n <div className=\"mt-1 flex items-center gap-1.5\">\n <RatingStars rating={service.providerRating} />\n <span className=\"text-xs font-medium text-text-primary\">{service.providerRating}</span>\n </div>\n </div>\n </div>\n <span\n className={cn(\n 'inline-flex shrink-0 rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n getStatusStyles(service.status)\n )}\n >\n {service.status}\n </span>\n </div>\n\n {/* Description */}\n <p className=\"mb-4 text-xs text-text-secondary line-clamp-2\">{service.description}</p>\n\n {/* Facts grid — Duration + Price (mock parity) */}\n <div className=\"mb-4 grid grid-cols-2 gap-3\">\n <div className=\"rounded-md bg-bg-sunken/50 p-2.5\">\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3 w-3\" />\n Est. Duration\n </p>\n <p className=\"mt-0.5 text-sm font-semibold text-text-primary\">{service.estimatedDuration}</p>\n </div>\n <div className=\"rounded-md bg-bg-sunken/50 p-2.5\">\n <p className=\"text-xs text-text-secondary\">Price Range</p>\n <p className=\"mt-0.5 text-sm font-semibold text-text-primary\">{service.priceRange}</p>\n </div>\n </div>\n\n {/* Consultation fee */}\n <div className=\"mb-3 text-xs\">\n {service.consultationFee > 0 ? (\n <span className=\"text-text-secondary\">\n Consultation:{' '}\n <span className=\"font-medium text-text-primary\">{formatCurrency(service.consultationFee)}</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 font-medium text-status-success-text\">Free consultation</span>\n )}\n </div>\n\n {/* Documents Required (collapsible) */}\n {service.documentsRequired.length > 0 && (\n <div className=\"mb-4\">\n <button\n onClick={() => setShowDocs(!showDocs)}\n aria-expanded={showDocs}\n className=\"text-xs font-medium text-accent-blue hover:underline\"\n >\n {showDocs ? 'Hide' : 'Show'} required documents ({service.documentsRequired.length})\n </button>\n {showDocs && (\n <ul className=\"mt-1.5 space-y-1\">\n {service.documentsRequired.map((doc, i) => (\n <li key={i} className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <span className=\"h-1 w-1 shrink-0 rounded-full bg-text-secondary/50\" />\n {doc}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Action */}\n <button\n onClick={() => navigate(`../legal/${service.id}`)}\n disabled={service.status === 'unavailable'}\n className={cn(\n 'mt-auto w-full rounded-md px-4 py-2 text-xs font-medium transition-colors',\n service.status === 'unavailable'\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover'\n )}\n >\n {service.status === 'unavailable' ? 'Currently Unavailable' : 'Book Now'}\n </button>\n </div>\n );\n}\n\nexport function LegalPage() {\n const [activeCategory, setActiveCategory] = useState<CategoryTab>('all');\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const pagination = useServerPagination(PAGE_SIZE);\n const { setPage } = pagination;\n\n // Debounce the search box so we don't refetch on every keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n // Server-side filter — category + search are resolved by the subgraph.\n const serverFilter = useMemo<LegalServiceFilterInput | undefined>(() => {\n const filter: LegalServiceFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (activeCategory !== 'all') filter.category = activeCategory;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, activeCategory]);\n\n // Reset to the first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: services, loading } = useLegalServices({ filter: serverFilter, pagination: pagination.pagination });\n\n const hasNextPage = services.length >= pagination.pageSize;\n\n return (\n <PageLayout\n title=\"Legal Services\"\n description=\"Professional legal solutions for property transactions and documentation\"\n purpose=\"Connect with verified property lawyers for the legal work behind every deal — title verification, rent agreements, registration, dispute advisory, and document review. Browse by category, compare ratings and fees, and book a consultation.\"\n actions={\n <span className=\"inline-flex items-center gap-1 text-xs text-status-success-text\">\n <Shield className=\"h-3.5 w-3.5\" />\n Legally Compliant\n </span>\n }\n >\n {/* Category Tabs — primary control zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"flex flex-wrap items-center gap-2 p-3\">\n {categoryTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => setActiveCategory(tab.value)}\n className={cn(\n 'rounded-full px-4 py-1.5 text-sm font-medium transition-colors',\n activeCategory === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {tab.label}\n </button>\n ))}\n </EmphasisPanel>\n\n {/* Search */}\n <FilterBar searchValue={search} onSearchChange={setSearch} searchPlaceholder=\"Search legal services...\" />\n\n <NextSteps\n storageKey=\"housingvista-legal\"\n steps={[\n {\n id: 'verify-title',\n label: 'Verify a property title',\n description: 'The first legal check before any purchase — find a title-search expert.',\n onClick: () => setActiveCategory('title_search'),\n },\n {\n id: 'rent-agreement',\n label: 'Draft or review a rent agreement',\n description: 'Get a lawyer to prepare or vet your lease paperwork.',\n onClick: () => setActiveCategory('lease_review'),\n },\n {\n id: 'registration',\n label: 'Handle property registration',\n description: 'Find help to register a deal with the authorities.',\n onClick: () => setActiveCategory('registration'),\n },\n ]}\n />\n\n {/* Service Cards */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : services.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {services.map((service) => (\n <LegalServiceCard key={service.id} service={service} />\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Scale className=\"h-12 w-12\" />}\n title=\"No legal services found\"\n description=\"Try adjusting your search or category filter.\"\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"LegalPage.js","names":[],"sources":["../../../../src/housingvista/pages/legal/LegalPage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Scale,\n Star,\n Clock,\n FileText,\n Search as SearchIcon,\n Shield,\n Gavel,\n BookOpen,\n ClipboardCheck,\n} from 'lucide-react';\nimport { EmphasisPanel, NextSteps, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, EmptyState, LoadingSkeleton } from '../../components';\nimport { useLegalServices, type LegalServiceFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn, formatCurrency } from '../../utils/helpers';\nimport type { LegalService } from '../../types';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst PAGE_SIZE = 9;\n\ntype CategoryTab = 'all' | 'title_search' | 'lease_review' | 'dispute_resolution' | 'registration' | 'compliance';\n\nconst categoryTabs: { value: CategoryTab; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'title_search', label: 'Title Verification' },\n { value: 'lease_review', label: 'Rent Agreement' },\n { value: 'dispute_resolution', label: 'Advisory' },\n { value: 'registration', label: 'Registration' },\n { value: 'compliance', label: 'Document Review' },\n];\n\nfunction getCategoryIcon(category: string) {\n switch (category) {\n case 'title_search':\n return <SearchIcon className=\"h-4 w-4\" />;\n case 'lease_review':\n return <FileText className=\"h-4 w-4\" />;\n case 'dispute_resolution':\n return <Gavel className=\"h-4 w-4\" />;\n case 'registration':\n return <ClipboardCheck className=\"h-4 w-4\" />;\n case 'compliance':\n return <BookOpen className=\"h-4 w-4\" />;\n default:\n return <Scale className=\"h-4 w-4\" />;\n }\n}\n\nfunction getStatusStyles(status: string) {\n switch (status) {\n case 'available':\n return 'bg-status-success-bg-subtle text-status-success-text';\n case 'busy':\n return 'bg-status-warning-bg-subtle text-status-warning-text';\n case 'unavailable':\n return 'bg-status-error-bg-subtle text-status-error-text';\n default:\n return 'bg-bg-sunken text-text-secondary';\n }\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5 text-status-warning-text\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn('h-3 w-3', i < Math.floor(rating) ? 'fill-current' : 'fill-none text-text-secondary/30')}\n />\n ))}\n </div>\n );\n}\n\nfunction LegalServiceCard({ service }: { service: LegalService }) {\n const navigate = useNavigate();\n const [showDocs, setShowDocs] = useState(false);\n\n return (\n <div className=\"flex flex-col rounded-card border border-border-seam bg-bg-surface p-5 shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2\">\n {/* Header */}\n <div className=\"mb-3 flex items-start justify-between gap-3\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-accent-blue-subtle text-accent-blue\">\n {getCategoryIcon(service.category)}\n </div>\n <div className=\"min-w-0\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{service.title}</h3>\n <p className=\"truncate text-xs text-text-secondary\">{service.providerName}</p>\n <div className=\"mt-1 flex items-center gap-1.5\">\n <RatingStars rating={service.providerRating} />\n <span className=\"text-xs font-medium text-text-primary\">{service.providerRating}</span>\n </div>\n </div>\n </div>\n <span\n className={cn(\n 'inline-flex shrink-0 rounded-full px-2 py-0.5 text-xs font-medium capitalize',\n getStatusStyles(service.status)\n )}\n >\n {service.status}\n </span>\n </div>\n\n {/* Description */}\n <p className=\"mb-4 text-xs text-text-secondary line-clamp-2\">{service.description}</p>\n\n {/* Facts grid — Duration + Price (mock parity) */}\n <div className=\"mb-4 grid grid-cols-2 gap-3\">\n <div className=\"rounded-md bg-bg-sunken/50 p-2.5\">\n <p className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Clock className=\"h-3 w-3\" />\n Est. Duration\n </p>\n <p className=\"mt-0.5 text-sm font-semibold text-text-primary\">{service.estimatedDuration}</p>\n </div>\n <div className=\"rounded-md bg-bg-sunken/50 p-2.5\">\n <p className=\"text-xs text-text-secondary\">Price Range</p>\n <p className=\"mt-0.5 text-sm font-semibold text-text-primary\">{service.priceRange}</p>\n </div>\n </div>\n\n {/* Consultation fee */}\n <div className=\"mb-3 text-xs\">\n {service.consultationFee > 0 ? (\n <span className=\"text-text-secondary\">\n Consultation:{' '}\n <span className=\"font-medium text-text-primary\">{formatCurrency(service.consultationFee)}</span>\n </span>\n ) : (\n <span className=\"inline-flex items-center gap-1 font-medium text-status-success-text\">Free consultation</span>\n )}\n </div>\n\n {/* Documents Required (collapsible) */}\n {service.documentsRequired.length > 0 && (\n <div className=\"mb-4\">\n <button\n onClick={() => setShowDocs(!showDocs)}\n aria-expanded={showDocs}\n className=\"text-xs font-medium text-accent-blue hover:underline\"\n >\n {showDocs ? 'Hide' : 'Show'} required documents ({service.documentsRequired.length})\n </button>\n {showDocs && (\n <ul className=\"mt-1.5 space-y-1\">\n {service.documentsRequired.map((doc, i) => (\n <li key={i} className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <span className=\"h-1 w-1 shrink-0 rounded-full bg-text-secondary/50\" />\n {doc}\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n\n {/* Action */}\n <button\n onClick={() => navigate(`../legal/${service.id}`)}\n disabled={service.status === 'unavailable'}\n className={cn(\n 'mt-auto w-full rounded-md px-4 py-2 text-xs font-medium transition-colors',\n service.status === 'unavailable'\n ? 'cursor-not-allowed bg-bg-sunken text-text-secondary'\n : 'bg-action-primary-bg text-action-primary-text hover:bg-action-primary-bg-hover'\n )}\n >\n {service.status === 'unavailable' ? 'Currently Unavailable' : 'Book Now'}\n </button>\n </div>\n );\n}\n\nexport function LegalPage() {\n useTrackPageView('housingvista.legal.viewed');\n const [activeCategory, setActiveCategory] = useState<CategoryTab>('all');\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const pagination = useServerPagination(PAGE_SIZE);\n const { setPage } = pagination;\n\n // Debounce the search box so we don't refetch on every keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n // Server-side filter — category + search are resolved by the subgraph.\n const serverFilter = useMemo<LegalServiceFilterInput | undefined>(() => {\n const filter: LegalServiceFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (activeCategory !== 'all') filter.category = activeCategory;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, activeCategory]);\n\n // Reset to the first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: services, loading } = useLegalServices({ filter: serverFilter, pagination: pagination.pagination });\n\n const hasNextPage = services.length >= pagination.pageSize;\n\n return (\n <PageLayout\n title=\"Legal Services\"\n description=\"Professional legal solutions for property transactions and documentation\"\n purpose=\"Connect with verified property lawyers for the legal work behind every deal — title verification, rent agreements, registration, dispute advisory, and document review. Browse by category, compare ratings and fees, and book a consultation.\"\n actions={\n <span className=\"inline-flex items-center gap-1 text-xs text-status-success-text\">\n <Shield className=\"h-3.5 w-3.5\" />\n Legally Compliant\n </span>\n }\n >\n {/* Category Tabs — primary control zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"flex flex-wrap items-center gap-2 p-3\">\n {categoryTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => setActiveCategory(tab.value)}\n className={cn(\n 'rounded-full px-4 py-1.5 text-sm font-medium transition-colors',\n activeCategory === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {tab.label}\n </button>\n ))}\n </EmphasisPanel>\n\n {/* Search */}\n <FilterBar searchValue={search} onSearchChange={setSearch} searchPlaceholder=\"Search legal services...\" />\n\n <NextSteps\n storageKey=\"housingvista-legal\"\n steps={[\n {\n id: 'verify-title',\n label: 'Verify a property title',\n description: 'The first legal check before any purchase — find a title-search expert.',\n onClick: () => setActiveCategory('title_search'),\n },\n {\n id: 'rent-agreement',\n label: 'Draft or review a rent agreement',\n description: 'Get a lawyer to prepare or vet your lease paperwork.',\n onClick: () => setActiveCategory('lease_review'),\n },\n {\n id: 'registration',\n label: 'Handle property registration',\n description: 'Find help to register a deal with the authorities.',\n onClick: () => setActiveCategory('registration'),\n },\n ]}\n />\n\n {/* Service Cards */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : services.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {services.map((service) => (\n <LegalServiceCard key={service.id} service={service} />\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Scale className=\"h-12 w-12\" />}\n title=\"No legal services found\"\n description=\"Try adjusting your search or category filter.\"\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"LegalServiceDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/legal/LegalServiceDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA0EH,wBAAgB,sBAAsB,gCA+NrC"}
1
+ {"version":3,"file":"LegalServiceDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/legal/LegalServiceDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2EH,wBAAgB,sBAAsB,gCAiOrC"}