@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
@@ -5,8 +5,9 @@ import { StatusBadge as a } from "../../components/StatusBadge.js";
5
5
  import { EmptyState as o } from "../../components/EmptyState.js";
6
6
  import { ChartCard as s } from "../../components/ChartCard.js";
7
7
  import { FilterBar as c } from "../../components/FilterBar.js";
8
- import { useCreateInvestment as l, useInvestments as u, useProperties as ee } from "../../hooks/index.js";
9
- import { notify as d } from "../../lib/toast.js";
8
+ import { useTrackPageView as l } from "../../hooks/useHousingVistaAnalytics.js";
9
+ import { useCreateInvestment as u, useInvestments as d, useProperties as ee } from "../../hooks/index.js";
10
+ import { notify as f } from "../../lib/toast.js";
10
11
  import "../../components/index.js";
11
12
  import { useServerPagination as te } from "../../hooks/useServerPagination.js";
12
13
  import { Tooltip as ne } from "../../../node_modules/recharts/es6/component/Tooltip.js";
@@ -14,11 +15,11 @@ import { ResponsiveContainer as re } from "../../../node_modules/recharts/es6/co
14
15
  import { Cell as ie } from "../../../node_modules/recharts/es6/component/Cell.js";
15
16
  import { Pie as ae } from "../../../node_modules/recharts/es6/polar/Pie.js";
16
17
  import { PieChart as oe } from "../../../node_modules/recharts/es6/chart/PieChart.js";
17
- import { useEffect as se, useMemo as f, useState as p } from "react";
18
- import { ArrowDownRight as ce, ArrowUpRight as le, BarChart3 as ue, Building as de, Calendar as fe, DollarSign as pe, Eye as me, PieChart as m, Plus as h, Target as he, TrendingUp as g } from "lucide-react";
19
- import { useNavigate as ge } from "react-router-dom";
20
- import { Fragment as _e, jsx as _, jsxs as v } from "react/jsx-runtime";
21
- import { Button as y, EmphasisPanel as ve, NextSteps as ye, Pagination as be, ResponsiveDialog as xe, ResponsiveDialogContent as Se, ResponsiveDialogDescription as Ce, ResponsiveDialogFooter as we, ResponsiveDialogHeader as Te, ResponsiveDialogTitle as Ee } from "@burdenoff/fe-libs/ui";
18
+ import { useEffect as se, useMemo as p, useState as m } from "react";
19
+ import { ArrowDownRight as ce, ArrowUpRight as le, BarChart3 as ue, Building as de, Calendar as fe, DollarSign as pe, Eye as me, PieChart as h, Plus as g, Target as he, TrendingUp as ge } from "lucide-react";
20
+ import { useNavigate as _e } from "react-router-dom";
21
+ import { Fragment as ve, jsx as _, jsxs as v } from "react/jsx-runtime";
22
+ import { Button as y, EmphasisPanel as ye, NextSteps as be, Pagination as xe, ResponsiveDialog as Se, ResponsiveDialogContent as Ce, ResponsiveDialogDescription as we, ResponsiveDialogFooter as Te, ResponsiveDialogHeader as Ee, ResponsiveDialogTitle as De } from "@burdenoff/fe-libs/ui";
22
23
  //#region src/housingvista/pages/investments/InvestmentsPage.tsx
23
24
  var b = "h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]", x = [
24
25
  "var(--color-chart-1)",
@@ -26,19 +27,19 @@ var b = "h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 t
26
27
  "var(--color-chart-3)",
27
28
  "var(--color-chart-4)",
28
29
  "var(--color-chart-5)"
29
- ], De = {
30
+ ], Oe = {
30
31
  background: "var(--color-bg-surface)",
31
32
  border: "1px solid var(--color-border-subtle)",
32
33
  borderRadius: 10,
33
34
  fontSize: 12,
34
35
  boxShadow: "0 8px 24px rgb(0 0 0 / 0.12)"
35
- }, Oe = {
36
+ }, ke = {
36
37
  full_ownership: "Full ownership",
37
38
  fractional: "Fractional",
38
39
  reits: "REITs",
39
40
  fund: "Fund"
40
41
  };
41
- function ke(e) {
42
+ function Ae(e) {
42
43
  switch (e) {
43
44
  case "low": return "success";
44
45
  case "medium": return "warning";
@@ -46,7 +47,7 @@ function ke(e) {
46
47
  default: return "muted";
47
48
  }
48
49
  }
49
- var Ae = [
50
+ var je = [
50
51
  {
51
52
  value: "all",
52
53
  label: "All"
@@ -63,7 +64,7 @@ var Ae = [
63
64
  value: "funding",
64
65
  label: "Funding"
65
66
  }
66
- ], je = [
67
+ ], Me = [
67
68
  {
68
69
  value: "full_ownership",
69
70
  label: "Full ownership"
@@ -80,7 +81,7 @@ var Ae = [
80
81
  value: "fund",
81
82
  label: "Fund"
82
83
  }
83
- ], Me = [
84
+ ], Ne = [
84
85
  {
85
86
  value: "draft",
86
87
  label: "Draft"
@@ -105,7 +106,7 @@ var Ae = [
105
106
  value: "closed",
106
107
  label: "Closed"
107
108
  }
108
- ], Ne = [
109
+ ], Pe = [
109
110
  {
110
111
  value: "low",
111
112
  label: "Low"
@@ -131,13 +132,13 @@ function w(e, t) {
131
132
  function T(e) {
132
133
  return e instanceof Date ? Number.isNaN(e.getTime()) ? "" : e.toISOString() : typeof e == "string" ? e : "";
133
134
  }
134
- function Pe(e) {
135
+ function Fe(e) {
135
136
  let t = T(e);
136
137
  if (!t) return "—";
137
138
  let r = new Date(t).getTime();
138
139
  return Number.isNaN(r) ? "—" : n(t);
139
140
  }
140
- function Fe(e) {
141
+ function Ie(e) {
141
142
  switch (e) {
142
143
  case "active": return "success";
143
144
  case "funding": return "warning";
@@ -148,51 +149,52 @@ function Fe(e) {
148
149
  default: return "default";
149
150
  }
150
151
  }
151
- function Ie(e) {
152
+ function Le(e) {
152
153
  return e > 0 ? "text-status-success-text" : e < 0 ? "text-status-error-text" : "text-text-secondary";
153
154
  }
154
155
  function E() {
155
- let n = ge(), T = te(10), [E, Le] = p(""), [Re, ze] = p(""), [D, Be] = p("all");
156
+ l("housingvista.investment.viewed");
157
+ let n = _e(), T = te(10), [E, Re] = m(""), [ze, Be] = m(""), [D, Ve] = m("all");
156
158
  se(() => {
157
- let e = setTimeout(() => ze(E), 300);
159
+ let e = setTimeout(() => Be(E), 300);
158
160
  return () => clearTimeout(e);
159
161
  }, [E]);
160
- let { data: O } = u({
162
+ let { data: O } = d({
161
163
  filter: {
162
- search: Re.trim() || void 0,
164
+ search: ze.trim() || void 0,
163
165
  status: D === "all" ? void 0 : D
164
166
  },
165
167
  pagination: T.pagination
166
- }), { data: k } = u({ pagination: {
168
+ }), { data: k } = d({ pagination: {
167
169
  limit: 100,
168
170
  offset: 0
169
171
  } }), { data: A } = ee({ pagination: {
170
172
  limit: 50,
171
173
  offset: 0
172
- } }), { createInvestment: Ve, loading: j } = l(), He = (e) => {
173
- Le(e), T.setPage(1);
174
+ } }), { createInvestment: He, loading: j } = u(), Ue = (e) => {
175
+ Re(e), T.setPage(1);
174
176
  }, M = (e) => {
175
- Be(e), T.setPage(1);
176
- }, [Ue, N] = p(!1), [P, F] = p(""), [I, L] = p(""), [R, z] = p("full_ownership"), [B, V] = p("draft"), [H, U] = p("medium"), [W, G] = p(""), [K, q] = p(""), [J, Y] = p(""), X = () => {
177
+ Ve(e), T.setPage(1);
178
+ }, [We, N] = m(!1), [P, F] = m(""), [I, L] = m(""), [R, z] = m("full_ownership"), [B, V] = m("draft"), [H, U] = m("medium"), [W, G] = m(""), [K, q] = m(""), [J, Y] = m(""), X = () => {
177
179
  F(""), L(""), z("full_ownership"), V("draft"), U("medium"), G(""), q(""), Y("");
178
180
  }, Z = () => {
179
181
  X(), N(!0);
180
- }, We = async (e) => {
182
+ }, Ge = async (e) => {
181
183
  if (e.preventDefault(), !P) {
182
- d.warning("Select a property");
184
+ f.warning("Select a property");
183
185
  return;
184
186
  }
185
187
  if (!I.trim()) {
186
- d.warning("Enter an investment title");
188
+ f.warning("Enter an investment title");
187
189
  return;
188
190
  }
189
191
  let t = Number(W);
190
192
  if (!Number.isFinite(t) || t <= 0) {
191
- d.warning("Enter a valid total value");
193
+ f.warning("Enter a valid total value");
192
194
  return;
193
195
  }
194
196
  try {
195
- await Ve({
197
+ await He({
196
198
  propertyId: P,
197
199
  title: I.trim(),
198
200
  status: B,
@@ -201,11 +203,11 @@ function E() {
201
203
  totalValue: t,
202
204
  startDate: K ? new Date(K).toISOString() : void 0,
203
205
  maturityDate: J ? new Date(J).toISOString() : void 0
204
- }), d.success("Investment created", `${I.trim()} was added to your portfolio.`), N(!1), X();
206
+ }), f.success("Investment created", `${I.trim()} was added to your portfolio.`), N(!1), X();
205
207
  } catch (e) {
206
- d.error("Could not create investment", e.message);
208
+ f.error("Could not create investment", e.message);
207
209
  }
208
- }, Q = f(() => {
210
+ }, Q = p(() => {
209
211
  let e = k.reduce((e, t) => e + w(t.investors, "investmentAmount"), 0), t = k.reduce((e, t) => e + w(t.returns, "amount"), 0);
210
212
  return {
211
213
  totalInvested: e,
@@ -214,7 +216,7 @@ function E() {
214
216
  activeCount: k.filter((e) => e.status === "active").length,
215
217
  returnPct: e > 0 ? t / e * 100 : 0
216
218
  };
217
- }, [k]), $ = f(() => {
219
+ }, [k]), $ = p(() => {
218
220
  let e = /* @__PURE__ */ new Map();
219
221
  for (let t of k) {
220
222
  let n = w(t.investors, "investmentAmount") + w(t.returns, "amount") || S(t.totalValue), r = t.investmentType;
@@ -222,7 +224,7 @@ function E() {
222
224
  }
223
225
  let t = Array.from(e.entries()).filter(([, e]) => e > 0).map(([e, t], n) => ({
224
226
  type: e,
225
- label: Oe[e] ?? e.replace("_", " "),
227
+ label: ke[e] ?? e.replace("_", " "),
226
228
  value: t,
227
229
  color: x[n % x.length]
228
230
  })).sort((e, t) => t.value - e.value);
@@ -238,10 +240,10 @@ function E() {
238
240
  actions: /* @__PURE__ */ v("button", {
239
241
  onClick: Z,
240
242
  className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover",
241
- children: [/* @__PURE__ */ _(h, { className: "h-4 w-4" }), "New Investment"]
243
+ children: [/* @__PURE__ */ _(g, { className: "h-4 w-4" }), "New Investment"]
242
244
  }),
243
245
  children: [
244
- /* @__PURE__ */ _(ve, {
246
+ /* @__PURE__ */ _(ye, {
245
247
  className: "p-4",
246
248
  children: /* @__PURE__ */ v("div", {
247
249
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
@@ -256,13 +258,13 @@ function E() {
256
258
  label: "Current Value",
257
259
  value: Q.currentValue,
258
260
  prefix: "$",
259
- icon: /* @__PURE__ */ _(g, { className: "h-4 w-4" })
261
+ icon: /* @__PURE__ */ _(ge, { className: "h-4 w-4" })
260
262
  }),
261
263
  /* @__PURE__ */ _(i, {
262
264
  label: "Total Returns",
263
265
  value: Q.totalReturns,
264
266
  prefix: "$",
265
- icon: /* @__PURE__ */ _(m, { className: "h-4 w-4" })
267
+ icon: /* @__PURE__ */ _(h, { className: "h-4 w-4" })
266
268
  }),
267
269
  /* @__PURE__ */ _(i, {
268
270
  label: "Active Investments",
@@ -272,7 +274,7 @@ function E() {
272
274
  ]
273
275
  })
274
276
  }),
275
- /* @__PURE__ */ _(ye, {
277
+ /* @__PURE__ */ _(be, {
276
278
  storageKey: "housingvista-investments",
277
279
  steps: [
278
280
  {
@@ -300,7 +302,7 @@ function E() {
300
302
  }),
301
303
  /* @__PURE__ */ _("div", {
302
304
  className: "flex flex-wrap items-center gap-2",
303
- children: Ae.map((t) => /* @__PURE__ */ _("button", {
305
+ children: je.map((t) => /* @__PURE__ */ _("button", {
304
306
  onClick: () => M(t.value),
305
307
  className: e("rounded-md px-3 py-1.5 text-sm font-medium transition-colors", D === t.value ? "bg-action-primary-bg text-action-primary-text" : "bg-bg-sunken text-text-secondary hover:text-text-primary"),
306
308
  children: t.label
@@ -308,7 +310,7 @@ function E() {
308
310
  }),
309
311
  /* @__PURE__ */ _(c, {
310
312
  searchValue: E,
311
- onSearchChange: He,
313
+ onSearchChange: Ue,
312
314
  searchPlaceholder: "Search by property or investment title..."
313
315
  }),
314
316
  /* @__PURE__ */ v("p", {
@@ -325,7 +327,7 @@ function E() {
325
327
  className: "grid grid-cols-1 gap-6 xl:grid-cols-3",
326
328
  children: [/* @__PURE__ */ _("div", {
327
329
  className: "space-y-4 xl:col-span-2",
328
- children: O.length > 0 ? /* @__PURE__ */ v(_e, { children: [/* @__PURE__ */ _("div", {
330
+ children: O.length > 0 ? /* @__PURE__ */ v(ve, { children: [/* @__PURE__ */ _("div", {
329
331
  className: "space-y-4",
330
332
  children: O.map((r) => {
331
333
  let i = r.property?.title ?? "Untitled property", o = w(r.investors, "investmentAmount"), s = w(r.returns, "amount"), c = o + s, l = o > 0 ? s / o * 100 : 0, u = C(r.returns).length;
@@ -353,7 +355,7 @@ function E() {
353
355
  }),
354
356
  /* @__PURE__ */ _(a, {
355
357
  label: r.status,
356
- variant: Fe(r.status)
358
+ variant: Ie(r.status)
357
359
  }),
358
360
  /* @__PURE__ */ _(a, {
359
361
  label: r.investmentType.replace("_", " "),
@@ -382,7 +384,7 @@ function E() {
382
384
  className: "text-text-secondary",
383
385
  children: "Total Return"
384
386
  }), /* @__PURE__ */ v("div", {
385
- className: e("font-medium", Ie(s)),
387
+ className: e("font-medium", Le(s)),
386
388
  children: [/* @__PURE__ */ v("div", {
387
389
  className: "flex items-center gap-1",
388
390
  children: [
@@ -402,7 +404,7 @@ function E() {
402
404
  className: "mt-1",
403
405
  children: /* @__PURE__ */ _(a, {
404
406
  label: `${r.riskLevel} risk`,
405
- variant: ke(r.riskLevel),
407
+ variant: Ae(r.riskLevel),
406
408
  dot: !0
407
409
  })
408
410
  })] })
@@ -414,9 +416,9 @@ function E() {
414
416
  /* @__PURE__ */ v("span", {
415
417
  className: "flex items-center gap-1",
416
418
  children: [
417
- /* @__PURE__ */ _(g, { className: "h-3 w-3" }),
419
+ /* @__PURE__ */ _(ge, { className: "h-3 w-3" }),
418
420
  "Start: ",
419
- Pe(r.startDate)
421
+ Fe(r.startDate)
420
422
  ]
421
423
  }),
422
424
  /* @__PURE__ */ v("span", {
@@ -454,7 +456,7 @@ function E() {
454
456
  })
455
457
  }, r.id);
456
458
  })
457
- }), /* @__PURE__ */ _(be, {
459
+ }), /* @__PURE__ */ _(xe, {
458
460
  page: T.page,
459
461
  pageSize: T.pageSize,
460
462
  hasNextPage: O.length >= T.pageSize,
@@ -463,13 +465,13 @@ function E() {
463
465
  onPageSizeChange: T.setPageSize
464
466
  })] }) : /* @__PURE__ */ _(o, {
465
467
  illustration: "empty-search",
466
- icon: /* @__PURE__ */ _(m, { className: "h-12 w-12" }),
468
+ icon: /* @__PURE__ */ _(h, { className: "h-12 w-12" }),
467
469
  title: "No investments found",
468
470
  description: "Try adjusting your search criteria or start a new investment.",
469
471
  action: /* @__PURE__ */ v("button", {
470
472
  onClick: Z,
471
473
  className: "inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover",
472
- children: [/* @__PURE__ */ _(h, { className: "h-4 w-4" }), "New Investment"]
474
+ children: [/* @__PURE__ */ _(g, { className: "h-4 w-4" }), "New Investment"]
473
475
  })
474
476
  })
475
477
  }), $.rows.length > 0 && /* @__PURE__ */ _("aside", {
@@ -493,7 +495,7 @@ function E() {
493
495
  strokeWidth: 2,
494
496
  children: $.rows.map((e) => /* @__PURE__ */ _(ie, { fill: e.color }, e.type))
495
497
  }), /* @__PURE__ */ _(ne, {
496
- contentStyle: De,
498
+ contentStyle: Oe,
497
499
  formatter: (e, n, r) => [t(e), r?.payload?.label]
498
500
  })] })
499
501
  }), /* @__PURE__ */ v("div", {
@@ -528,15 +530,15 @@ function E() {
528
530
  })
529
531
  })]
530
532
  }),
531
- /* @__PURE__ */ _(xe, {
532
- open: Ue,
533
+ /* @__PURE__ */ _(Se, {
534
+ open: We,
533
535
  onOpenChange: N,
534
- children: /* @__PURE__ */ _(Se, {
536
+ children: /* @__PURE__ */ _(Ce, {
535
537
  className: "sm:max-w-md",
536
538
  children: /* @__PURE__ */ v("form", {
537
- onSubmit: We,
539
+ onSubmit: Ge,
538
540
  children: [
539
- /* @__PURE__ */ v(Te, { children: [/* @__PURE__ */ _(Ee, { children: "New investment" }), /* @__PURE__ */ _(Ce, { children: "Register a new holding against one of your properties." })] }),
541
+ /* @__PURE__ */ v(Ee, { children: [/* @__PURE__ */ _(De, { children: "New investment" }), /* @__PURE__ */ _(we, { children: "Register a new holding against one of your properties." })] }),
540
542
  /* @__PURE__ */ v("div", {
541
543
  className: "space-y-3 py-2",
542
544
  children: [
@@ -577,7 +579,7 @@ function E() {
577
579
  value: R,
578
580
  onChange: (e) => z(e.target.value),
579
581
  className: b,
580
- children: je.map((e) => /* @__PURE__ */ _("option", {
582
+ children: Me.map((e) => /* @__PURE__ */ _("option", {
581
583
  value: e.value,
582
584
  children: e.label
583
585
  }, e.value))
@@ -588,7 +590,7 @@ function E() {
588
590
  value: B,
589
591
  onChange: (e) => V(e.target.value),
590
592
  className: b,
591
- children: Me.map((e) => /* @__PURE__ */ _("option", {
593
+ children: Ne.map((e) => /* @__PURE__ */ _("option", {
592
594
  value: e.value,
593
595
  children: e.label
594
596
  }, e.value))
@@ -603,7 +605,7 @@ function E() {
603
605
  value: H,
604
606
  onChange: (e) => U(e.target.value),
605
607
  className: b,
606
- children: Ne.map((e) => /* @__PURE__ */ _("option", {
608
+ children: Pe.map((e) => /* @__PURE__ */ _("option", {
607
609
  value: e.value,
608
610
  children: e.label
609
611
  }, e.value))
@@ -643,7 +645,7 @@ function E() {
643
645
  })
644
646
  ]
645
647
  }),
646
- /* @__PURE__ */ v(we, { children: [/* @__PURE__ */ _(y, {
648
+ /* @__PURE__ */ v(Te, { children: [/* @__PURE__ */ _(y, {
647
649
  type: "button",
648
650
  variant: "outline",
649
651
  onClick: () => N(!1),
@@ -1 +1 @@
1
- {"version":3,"file":"InvestmentsPage.js","names":[],"sources":["../../../../src/housingvista/pages/investments/InvestmentsPage.tsx"],"sourcesContent":["import { useState, useMemo, useEffect, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n DollarSign,\n TrendingUp,\n PieChart,\n BarChart3,\n Plus,\n Building,\n ArrowUpRight,\n ArrowDownRight,\n Eye,\n Target,\n Calendar,\n} from 'lucide-react';\nimport {\n EmphasisPanel,\n NextSteps,\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { PieChart as RePieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';\nimport { PageLayout, StatCard, FilterBar, StatusBadge, EmptyState, ChartCard } from '../../components';\nimport { useInvestments, useCreateInvestment, useProperties } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport type { InvestmentStatus, InvestmentType } from '../../types';\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n// Full oklch chart tokens (see fe-libs theme) used for the allocation donut.\nconst CHART_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\nconst tooltipContentStyle: React.CSSProperties = {\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-subtle)',\n borderRadius: 10,\n fontSize: 12,\n boxShadow: '0 8px 24px rgb(0 0 0 / 0.12)',\n};\n\nconst investmentTypeLabels: Record<InvestmentType, string> = {\n full_ownership: 'Full ownership',\n fractional: 'Fractional',\n reits: 'REITs',\n fund: 'Fund',\n};\n\nfunction riskBadgeVariant(risk: string): 'success' | 'warning' | 'error' | 'muted' {\n switch (risk) {\n case 'low':\n return 'success';\n case 'medium':\n return 'warning';\n case 'high':\n return 'error';\n default:\n return 'muted';\n }\n}\n\nconst statusTabs: { value: InvestmentStatus | 'all'; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'active', label: 'Active' },\n { value: 'closed', label: 'Completed' },\n { value: 'funding', label: 'Funding' },\n];\n\nconst investmentTypeOptions: { value: InvestmentType; label: string }[] = [\n { value: 'full_ownership', label: 'Full ownership' },\n { value: 'fractional', label: 'Fractional' },\n { value: 'reits', label: 'REITs' },\n { value: 'fund', label: 'Fund' },\n];\n\nconst statusOptions: { value: InvestmentStatus; label: string }[] = [\n { value: 'draft', label: 'Draft' },\n { value: 'open', label: 'Open' },\n { value: 'funding', label: 'Funding' },\n { value: 'active', label: 'Active' },\n { value: 'mature', label: 'Mature' },\n { value: 'closed', label: 'Closed' },\n];\n\nconst riskOptions: { value: 'low' | 'medium' | 'high'; label: string }[] = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n];\n\n// ---------------------------------------------------------------------------\n// Safe accessors — `investors` and `returns` are opaque JSON columns and the\n// date fields arrive as ISO strings at runtime, so aggregates never trust the\n// domain type's shape.\n// ---------------------------------------------------------------------------\nfunction toNumber(value: unknown): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction safeArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction sumField(value: unknown, field: string): number {\n return safeArray(value).reduce<number>((sum, item) => {\n const rec = typeof item === 'object' && item !== null ? (item as Record<string, unknown>) : {};\n return sum + toNumber(rec[field]);\n }, 0);\n}\n\nfunction toIsoString(value: unknown): string {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? '' : value.toISOString();\n if (typeof value === 'string') return value;\n return '';\n}\n\nfunction formatDateSafe(value: unknown): string {\n const iso = toIsoString(value);\n if (!iso) return '—';\n const ms = new Date(iso).getTime();\n return Number.isNaN(ms) ? '—' : formatDate(iso);\n}\n\nfunction getStatusVariant(status: InvestmentStatus): 'success' | 'warning' | 'error' | 'info' | 'muted' | 'default' {\n switch (status) {\n case 'active':\n return 'success';\n case 'funding':\n return 'warning';\n case 'closed':\n case 'mature':\n return 'info';\n case 'draft':\n case 'open':\n return 'muted';\n default:\n return 'default';\n }\n}\n\nfunction getReturnColor(returnValue: number) {\n if (returnValue > 0) return 'text-status-success-text';\n if (returnValue < 0) return 'text-status-error-text';\n return 'text-text-secondary';\n}\n\nexport function InvestmentsPage() {\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [activeTab, setActiveTab] = useState<InvestmentStatus | 'all'>('all');\n\n // Debounce the raw search input into the value that feeds the server filter.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n const { data: investments } = useInvestments({\n filter: {\n search: debouncedSearch.trim() || undefined,\n status: activeTab === 'all' ? undefined : activeTab,\n },\n pagination: pagination.pagination,\n });\n // Portfolio summary reflects the whole portfolio, not just the current page.\n const { data: allInvestments } = useInvestments({ pagination: { limit: 100, offset: 0 } });\n const { data: properties } = useProperties({ pagination: { limit: 50, offset: 0 } });\n const { createInvestment, loading: creating } = useCreateInvestment();\n\n // Search and tab changes narrow the result set — always return to the first page.\n const handleSearchChange = (value: string) => {\n setSearch(value);\n pagination.setPage(1);\n };\n\n const handleTabChange = (tab: InvestmentStatus | 'all') => {\n setActiveTab(tab);\n pagination.setPage(1);\n };\n\n // Create-investment form state\n const [createOpen, setCreateOpen] = useState(false);\n const [propertyId, setPropertyId] = useState('');\n const [title, setTitle] = useState('');\n const [investmentType, setInvestmentType] = useState<InvestmentType>('full_ownership');\n const [status, setStatus] = useState<InvestmentStatus>('draft');\n const [riskLevel, setRiskLevel] = useState<'low' | 'medium' | 'high'>('medium');\n const [totalValue, setTotalValue] = useState('');\n const [startDate, setStartDate] = useState('');\n const [maturityDate, setMaturityDate] = useState('');\n\n const resetForm = () => {\n setPropertyId('');\n setTitle('');\n setInvestmentType('full_ownership');\n setStatus('draft');\n setRiskLevel('medium');\n setTotalValue('');\n setStartDate('');\n setMaturityDate('');\n };\n\n const openCreate = () => {\n resetForm();\n setCreateOpen(true);\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n if (!propertyId) {\n notify.warning('Select a property');\n return;\n }\n if (!title.trim()) {\n notify.warning('Enter an investment title');\n return;\n }\n const value = Number(totalValue);\n if (!Number.isFinite(value) || value <= 0) {\n notify.warning('Enter a valid total value');\n return;\n }\n try {\n await createInvestment({\n propertyId,\n title: title.trim(),\n status,\n investmentType,\n riskLevel,\n totalValue: value,\n startDate: startDate ? new Date(startDate).toISOString() : undefined,\n maturityDate: maturityDate ? new Date(maturityDate).toISOString() : undefined,\n });\n notify.success('Investment created', `${title.trim()} was added to your portfolio.`);\n setCreateOpen(false);\n resetForm();\n } catch (err) {\n notify.error('Could not create investment', (err as Error).message);\n }\n };\n\n const portfolioStats = useMemo(() => {\n const totalInvested = allInvestments.reduce((sum, inv) => sum + sumField(inv.investors, 'investmentAmount'), 0);\n const totalReturns = allInvestments.reduce((sum, inv) => sum + sumField(inv.returns, 'amount'), 0);\n const currentValue = totalInvested + totalReturns;\n const activeCount = allInvestments.filter((inv) => inv.status === 'active').length;\n const returnPct = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n return { totalInvested, currentValue, totalReturns, activeCount, returnPct };\n }, [allInvestments]);\n\n // Portfolio allocation by investment type, weighted by current value (invested\n // + returns) — real figures from every holding, never fabricated.\n const allocation = useMemo(() => {\n const byType = new Map<string, number>();\n for (const inv of allInvestments) {\n const invested = sumField(inv.investors, 'investmentAmount');\n const returns = sumField(inv.returns, 'amount');\n const value = invested + returns || toNumber(inv.totalValue);\n const key = inv.investmentType;\n byType.set(key, (byType.get(key) ?? 0) + value);\n }\n const rows = Array.from(byType.entries())\n .filter(([, value]) => value > 0)\n .map(([type, value], idx) => ({\n type,\n label: investmentTypeLabels[type as InvestmentType] ?? type.replace('_', ' '),\n value,\n color: CHART_COLORS[idx % CHART_COLORS.length],\n }))\n .sort((a, b) => b.value - a.value);\n const total = rows.reduce((s, r) => s + r.value, 0);\n return { rows, total };\n }, [allInvestments]);\n\n return (\n <PageLayout\n title=\"Investments\"\n description=\"Track your real estate investment portfolio and performance\"\n purpose=\"Follow every real-estate investment you hold in one portfolio — how much you put in, what it is worth now, the returns it has paid, and its risk level. Use it to judge performance and decide where to put your next dollar.\"\n actions={\n <button\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n >\n {/* Portfolio Summary Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label=\"Total Invested\"\n value={portfolioStats.totalInvested}\n prefix=\"$\"\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Current Value\"\n value={portfolioStats.currentValue}\n prefix=\"$\"\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Returns\"\n value={portfolioStats.totalReturns}\n prefix=\"$\"\n icon={<PieChart className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Active Investments\"\n value={portfolioStats.activeCount}\n icon={<BarChart3 className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-investments\"\n steps={[\n {\n id: 'review-active',\n label: 'Review your active investments',\n description: 'Filter to the active deals currently paying returns.',\n onClick: () => handleTabChange('active'),\n },\n {\n id: 'find-funding',\n label: 'Find funding opportunities',\n description: 'See deals still raising capital that you can join.',\n onClick: () => handleTabChange('funding'),\n },\n {\n id: 'open-detail',\n label: 'Open an investment for full details',\n description: 'Drill into returns, investors, and risk for any holding.',\n onClick: () => {\n const first = investments[0];\n if (first) navigate(`../investments/${first.id}`);\n },\n },\n ]}\n />\n\n {/* Filter Tabs */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => handleTabChange(tab.value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n activeTab === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Search */}\n <FilterBar\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder=\"Search by property or investment title...\"\n />\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n Showing {investments.length} {investments.length === 1 ? 'investment' : 'investments'} on this page\n </p>\n\n {/* Investment list (left) + portfolio allocation donut (aside) */}\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-3\">\n <div className=\"space-y-4 xl:col-span-2\">\n {investments.length > 0 ? (\n <>\n <div className=\"space-y-4\">\n {investments.map((investment) => {\n const propertyTitle = investment.property?.title ?? 'Untitled property';\n const totalInvested = sumField(investment.investors, 'investmentAmount');\n const totalReturns = sumField(investment.returns, 'amount');\n const currentValue = totalInvested + totalReturns;\n const returnPercentage = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n const returnsCount = safeArray(investment.returns).length;\n\n return (\n <div\n key={investment.id}\n className=\"cursor-pointer rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm transition-shadow hover:shadow-md\"\n onClick={() => navigate(`../investments/${investment.id}`)}\n >\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex-1\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-lg bg-bg-sunken p-2\">\n <Building className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex-1\">\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{propertyTitle}</h3>\n <StatusBadge label={investment.status} variant={getStatusVariant(investment.status)} />\n <StatusBadge label={investment.investmentType.replace('_', ' ')} variant=\"muted\" />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 text-sm sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-text-secondary\">Invested Amount</p>\n <p className=\"text-lg font-medium text-text-primary\">\n {formatCurrency(totalInvested)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Current Value</p>\n <p className=\"text-lg font-medium text-text-primary\">\n {formatCurrency(currentValue)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Total Return</p>\n <div className={cn('font-medium', getReturnColor(totalReturns))}>\n <div className=\"flex items-center gap-1\">\n {totalReturns > 0 && <ArrowUpRight className=\"h-3 w-3\" />}\n {totalReturns < 0 && <ArrowDownRight className=\"h-3 w-3\" />}\n {formatCurrency(totalReturns)}\n </div>\n <div className=\"text-sm\">{returnPercentage.toFixed(1)}%</div>\n </div>\n </div>\n <div>\n <p className=\"text-text-secondary\">Risk Level</p>\n <div className=\"mt-1\">\n <StatusBadge\n label={`${investment.riskLevel} risk`}\n variant={riskBadgeVariant(investment.riskLevel)}\n dot\n />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-5 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <TrendingUp className=\"h-3 w-3\" />\n Start: {formatDateSafe(investment.startDate)}\n </span>\n <span className=\"flex items-center gap-1\">\n <Target className=\"h-3 w-3\" />\n Type: {investment.investmentType.replace('_', ' ')}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Returns: {returnsCount} payments\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <div className=\"flex shrink-0 gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`../investments/${investment.id}`);\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={investments.length >= pagination.pageSize}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<PieChart className=\"h-12 w-12\" />}\n title=\"No investments found\"\n description=\"Try adjusting your search criteria or start a new investment.\"\n action={\n <button\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n />\n )}\n </div>\n\n {/* Portfolio Allocation — real value split by investment type */}\n {allocation.rows.length > 0 && (\n <aside className=\"xl:col-span-1\">\n <ChartCard title=\"Portfolio Allocation\" description=\"Current value by investment type\">\n <div className=\"relative h-52 w-full\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RePieChart>\n <Pie\n data={allocation.rows}\n dataKey=\"value\"\n nameKey=\"label\"\n innerRadius={56}\n outerRadius={82}\n paddingAngle={2}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n >\n {allocation.rows.map((entry) => (\n <Cell key={entry.type} fill={entry.color} />\n ))}\n </Pie>\n <Tooltip\n contentStyle={tooltipContentStyle}\n formatter={(value: number, _n, item) => [formatCurrency(value), item?.payload?.label]}\n />\n </RePieChart>\n </ResponsiveContainer>\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center\">\n <span className=\"text-xs text-text-secondary\">Total value</span>\n <span className=\"text-lg font-bold text-text-primary\">{formatCurrency(allocation.total)}</span>\n </div>\n </div>\n <ul className=\"mt-4 space-y-2.5\">\n {allocation.rows.map((entry) => (\n <li key={entry.type} className=\"flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-2\">\n <span className=\"h-2.5 w-2.5 rounded-full\" style={{ background: entry.color }} />\n <span className=\"text-text-primary\">{entry.label}</span>\n </span>\n <span className=\"font-medium text-text-secondary\">{formatCurrency(entry.value)}</span>\n </li>\n ))}\n </ul>\n </ChartCard>\n </aside>\n )}\n </div>\n\n {/* Create Investment dialog */}\n <ResponsiveDialog open={createOpen} onOpenChange={setCreateOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleCreate}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New investment</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a new holding against one of your properties.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Property *</label>\n <select\n required\n value={propertyId}\n onChange={(e) => setPropertyId(e.target.value)}\n className={inputClass}\n >\n <option value=\"\" disabled>\n {properties.length > 0 ? 'Select a property' : 'No properties available'}\n </option>\n {properties.map((property) => (\n <option key={property.id} value={property.id}>\n {property.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Title *</label>\n <input\n type=\"text\"\n required\n placeholder=\"e.g. Riverside Villa fractional stake\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n className={inputClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Type</label>\n <select\n value={investmentType}\n onChange={(e) => setInvestmentType(e.target.value as InvestmentType)}\n className={inputClass}\n >\n {investmentTypeOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Status</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as InvestmentStatus)}\n className={inputClass}\n >\n {statusOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Risk level</label>\n <select\n value={riskLevel}\n onChange={(e) => setRiskLevel(e.target.value as 'low' | 'medium' | 'high')}\n className={inputClass}\n >\n {riskOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Total value (USD) *</label>\n <input\n type=\"number\"\n required\n min={1}\n step=\"any\"\n placeholder=\"0\"\n value={totalValue}\n onChange={(e) => setTotalValue(e.target.value)}\n className={inputClass}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Start date</label>\n <input\n type=\"date\"\n value={startDate}\n onChange={(e) => setStartDate(e.target.value)}\n className={inputClass}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Maturity date</label>\n <input\n type=\"date\"\n value={maturityDate}\n onChange={(e) => setMaturityDate(e.target.value)}\n className={inputClass}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setCreateOpen(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={creating || !propertyId || !title.trim() || !totalValue}>\n {creating ? 'Creating…' : 'Create investment'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"InvestmentsPage.js","names":[],"sources":["../../../../src/housingvista/pages/investments/InvestmentsPage.tsx"],"sourcesContent":["import { useState, useMemo, useEffect, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n DollarSign,\n TrendingUp,\n PieChart,\n BarChart3,\n Plus,\n Building,\n ArrowUpRight,\n ArrowDownRight,\n Eye,\n Target,\n Calendar,\n} from 'lucide-react';\nimport {\n EmphasisPanel,\n NextSteps,\n Button,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n Pagination,\n} from '@burdenoff/fe-libs/ui';\nimport { PieChart as RePieChart, Pie, Cell, ResponsiveContainer, Tooltip } from 'recharts';\nimport { PageLayout, StatCard, FilterBar, StatusBadge, EmptyState, ChartCard } from '../../components';\nimport { useInvestments, useCreateInvestment, useProperties } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport type { InvestmentStatus, InvestmentType } from '../../types';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\n// Full oklch chart tokens (see fe-libs theme) used for the allocation donut.\nconst CHART_COLORS = [\n 'var(--color-chart-1)',\n 'var(--color-chart-2)',\n 'var(--color-chart-3)',\n 'var(--color-chart-4)',\n 'var(--color-chart-5)',\n];\nconst tooltipContentStyle: React.CSSProperties = {\n background: 'var(--color-bg-surface)',\n border: '1px solid var(--color-border-subtle)',\n borderRadius: 10,\n fontSize: 12,\n boxShadow: '0 8px 24px rgb(0 0 0 / 0.12)',\n};\n\nconst investmentTypeLabels: Record<InvestmentType, string> = {\n full_ownership: 'Full ownership',\n fractional: 'Fractional',\n reits: 'REITs',\n fund: 'Fund',\n};\n\nfunction riskBadgeVariant(risk: string): 'success' | 'warning' | 'error' | 'muted' {\n switch (risk) {\n case 'low':\n return 'success';\n case 'medium':\n return 'warning';\n case 'high':\n return 'error';\n default:\n return 'muted';\n }\n}\n\nconst statusTabs: { value: InvestmentStatus | 'all'; label: string }[] = [\n { value: 'all', label: 'All' },\n { value: 'active', label: 'Active' },\n { value: 'closed', label: 'Completed' },\n { value: 'funding', label: 'Funding' },\n];\n\nconst investmentTypeOptions: { value: InvestmentType; label: string }[] = [\n { value: 'full_ownership', label: 'Full ownership' },\n { value: 'fractional', label: 'Fractional' },\n { value: 'reits', label: 'REITs' },\n { value: 'fund', label: 'Fund' },\n];\n\nconst statusOptions: { value: InvestmentStatus; label: string }[] = [\n { value: 'draft', label: 'Draft' },\n { value: 'open', label: 'Open' },\n { value: 'funding', label: 'Funding' },\n { value: 'active', label: 'Active' },\n { value: 'mature', label: 'Mature' },\n { value: 'closed', label: 'Closed' },\n];\n\nconst riskOptions: { value: 'low' | 'medium' | 'high'; label: string }[] = [\n { value: 'low', label: 'Low' },\n { value: 'medium', label: 'Medium' },\n { value: 'high', label: 'High' },\n];\n\n// ---------------------------------------------------------------------------\n// Safe accessors — `investors` and `returns` are opaque JSON columns and the\n// date fields arrive as ISO strings at runtime, so aggregates never trust the\n// domain type's shape.\n// ---------------------------------------------------------------------------\nfunction toNumber(value: unknown): number {\n return typeof value === 'number' && Number.isFinite(value) ? value : 0;\n}\n\nfunction safeArray(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\nfunction sumField(value: unknown, field: string): number {\n return safeArray(value).reduce<number>((sum, item) => {\n const rec = typeof item === 'object' && item !== null ? (item as Record<string, unknown>) : {};\n return sum + toNumber(rec[field]);\n }, 0);\n}\n\nfunction toIsoString(value: unknown): string {\n if (value instanceof Date) return Number.isNaN(value.getTime()) ? '' : value.toISOString();\n if (typeof value === 'string') return value;\n return '';\n}\n\nfunction formatDateSafe(value: unknown): string {\n const iso = toIsoString(value);\n if (!iso) return '—';\n const ms = new Date(iso).getTime();\n return Number.isNaN(ms) ? '—' : formatDate(iso);\n}\n\nfunction getStatusVariant(status: InvestmentStatus): 'success' | 'warning' | 'error' | 'info' | 'muted' | 'default' {\n switch (status) {\n case 'active':\n return 'success';\n case 'funding':\n return 'warning';\n case 'closed':\n case 'mature':\n return 'info';\n case 'draft':\n case 'open':\n return 'muted';\n default:\n return 'default';\n }\n}\n\nfunction getReturnColor(returnValue: number) {\n if (returnValue > 0) return 'text-status-success-text';\n if (returnValue < 0) return 'text-status-error-text';\n return 'text-text-secondary';\n}\n\nexport function InvestmentsPage() {\n useTrackPageView('housingvista.investment.viewed');\n const navigate = useNavigate();\n const pagination = useServerPagination(10);\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [activeTab, setActiveTab] = useState<InvestmentStatus | 'all'>('all');\n\n // Debounce the raw search input into the value that feeds the server filter.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n const { data: investments } = useInvestments({\n filter: {\n search: debouncedSearch.trim() || undefined,\n status: activeTab === 'all' ? undefined : activeTab,\n },\n pagination: pagination.pagination,\n });\n // Portfolio summary reflects the whole portfolio, not just the current page.\n const { data: allInvestments } = useInvestments({ pagination: { limit: 100, offset: 0 } });\n const { data: properties } = useProperties({ pagination: { limit: 50, offset: 0 } });\n const { createInvestment, loading: creating } = useCreateInvestment();\n\n // Search and tab changes narrow the result set — always return to the first page.\n const handleSearchChange = (value: string) => {\n setSearch(value);\n pagination.setPage(1);\n };\n\n const handleTabChange = (tab: InvestmentStatus | 'all') => {\n setActiveTab(tab);\n pagination.setPage(1);\n };\n\n // Create-investment form state\n const [createOpen, setCreateOpen] = useState(false);\n const [propertyId, setPropertyId] = useState('');\n const [title, setTitle] = useState('');\n const [investmentType, setInvestmentType] = useState<InvestmentType>('full_ownership');\n const [status, setStatus] = useState<InvestmentStatus>('draft');\n const [riskLevel, setRiskLevel] = useState<'low' | 'medium' | 'high'>('medium');\n const [totalValue, setTotalValue] = useState('');\n const [startDate, setStartDate] = useState('');\n const [maturityDate, setMaturityDate] = useState('');\n\n const resetForm = () => {\n setPropertyId('');\n setTitle('');\n setInvestmentType('full_ownership');\n setStatus('draft');\n setRiskLevel('medium');\n setTotalValue('');\n setStartDate('');\n setMaturityDate('');\n };\n\n const openCreate = () => {\n resetForm();\n setCreateOpen(true);\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n if (!propertyId) {\n notify.warning('Select a property');\n return;\n }\n if (!title.trim()) {\n notify.warning('Enter an investment title');\n return;\n }\n const value = Number(totalValue);\n if (!Number.isFinite(value) || value <= 0) {\n notify.warning('Enter a valid total value');\n return;\n }\n try {\n await createInvestment({\n propertyId,\n title: title.trim(),\n status,\n investmentType,\n riskLevel,\n totalValue: value,\n startDate: startDate ? new Date(startDate).toISOString() : undefined,\n maturityDate: maturityDate ? new Date(maturityDate).toISOString() : undefined,\n });\n notify.success('Investment created', `${title.trim()} was added to your portfolio.`);\n setCreateOpen(false);\n resetForm();\n } catch (err) {\n notify.error('Could not create investment', (err as Error).message);\n }\n };\n\n const portfolioStats = useMemo(() => {\n const totalInvested = allInvestments.reduce((sum, inv) => sum + sumField(inv.investors, 'investmentAmount'), 0);\n const totalReturns = allInvestments.reduce((sum, inv) => sum + sumField(inv.returns, 'amount'), 0);\n const currentValue = totalInvested + totalReturns;\n const activeCount = allInvestments.filter((inv) => inv.status === 'active').length;\n const returnPct = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n return { totalInvested, currentValue, totalReturns, activeCount, returnPct };\n }, [allInvestments]);\n\n // Portfolio allocation by investment type, weighted by current value (invested\n // + returns) — real figures from every holding, never fabricated.\n const allocation = useMemo(() => {\n const byType = new Map<string, number>();\n for (const inv of allInvestments) {\n const invested = sumField(inv.investors, 'investmentAmount');\n const returns = sumField(inv.returns, 'amount');\n const value = invested + returns || toNumber(inv.totalValue);\n const key = inv.investmentType;\n byType.set(key, (byType.get(key) ?? 0) + value);\n }\n const rows = Array.from(byType.entries())\n .filter(([, value]) => value > 0)\n .map(([type, value], idx) => ({\n type,\n label: investmentTypeLabels[type as InvestmentType] ?? type.replace('_', ' '),\n value,\n color: CHART_COLORS[idx % CHART_COLORS.length],\n }))\n .sort((a, b) => b.value - a.value);\n const total = rows.reduce((s, r) => s + r.value, 0);\n return { rows, total };\n }, [allInvestments]);\n\n return (\n <PageLayout\n title=\"Investments\"\n description=\"Track your real estate investment portfolio and performance\"\n purpose=\"Follow every real-estate investment you hold in one portfolio — how much you put in, what it is worth now, the returns it has paid, and its risk level. Use it to judge performance and decide where to put your next dollar.\"\n actions={\n <button\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n >\n {/* Portfolio Summary Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label=\"Total Invested\"\n value={portfolioStats.totalInvested}\n prefix=\"$\"\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Current Value\"\n value={portfolioStats.currentValue}\n prefix=\"$\"\n icon={<TrendingUp className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Total Returns\"\n value={portfolioStats.totalReturns}\n prefix=\"$\"\n icon={<PieChart className=\"h-4 w-4\" />}\n />\n <StatCard\n label=\"Active Investments\"\n value={portfolioStats.activeCount}\n icon={<BarChart3 className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-investments\"\n steps={[\n {\n id: 'review-active',\n label: 'Review your active investments',\n description: 'Filter to the active deals currently paying returns.',\n onClick: () => handleTabChange('active'),\n },\n {\n id: 'find-funding',\n label: 'Find funding opportunities',\n description: 'See deals still raising capital that you can join.',\n onClick: () => handleTabChange('funding'),\n },\n {\n id: 'open-detail',\n label: 'Open an investment for full details',\n description: 'Drill into returns, investors, and risk for any holding.',\n onClick: () => {\n const first = investments[0];\n if (first) navigate(`../investments/${first.id}`);\n },\n },\n ]}\n />\n\n {/* Filter Tabs */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => handleTabChange(tab.value)}\n className={cn(\n 'rounded-md px-3 py-1.5 text-sm font-medium transition-colors',\n activeTab === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'bg-bg-sunken text-text-secondary hover:text-text-primary'\n )}\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Search */}\n <FilterBar\n searchValue={search}\n onSearchChange={handleSearchChange}\n searchPlaceholder=\"Search by property or investment title...\"\n />\n\n {/* Results count */}\n <p className=\"text-sm text-text-secondary\">\n Showing {investments.length} {investments.length === 1 ? 'investment' : 'investments'} on this page\n </p>\n\n {/* Investment list (left) + portfolio allocation donut (aside) */}\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-3\">\n <div className=\"space-y-4 xl:col-span-2\">\n {investments.length > 0 ? (\n <>\n <div className=\"space-y-4\">\n {investments.map((investment) => {\n const propertyTitle = investment.property?.title ?? 'Untitled property';\n const totalInvested = sumField(investment.investors, 'investmentAmount');\n const totalReturns = sumField(investment.returns, 'amount');\n const currentValue = totalInvested + totalReturns;\n const returnPercentage = totalInvested > 0 ? (totalReturns / totalInvested) * 100 : 0;\n const returnsCount = safeArray(investment.returns).length;\n\n return (\n <div\n key={investment.id}\n className=\"cursor-pointer rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm transition-shadow hover:shadow-md\"\n onClick={() => navigate(`../investments/${investment.id}`)}\n >\n <div className=\"flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div className=\"flex-1\">\n <div className=\"flex items-start gap-3\">\n <div className=\"rounded-lg bg-bg-sunken p-2\">\n <Building className=\"h-5 w-5 text-text-secondary\" />\n </div>\n <div className=\"flex-1\">\n <div className=\"mb-2 flex flex-wrap items-center gap-2\">\n <h3 className=\"text-lg font-semibold text-text-primary\">{propertyTitle}</h3>\n <StatusBadge label={investment.status} variant={getStatusVariant(investment.status)} />\n <StatusBadge label={investment.investmentType.replace('_', ' ')} variant=\"muted\" />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 text-sm sm:grid-cols-2 lg:grid-cols-4\">\n <div>\n <p className=\"text-text-secondary\">Invested Amount</p>\n <p className=\"text-lg font-medium text-text-primary\">\n {formatCurrency(totalInvested)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Current Value</p>\n <p className=\"text-lg font-medium text-text-primary\">\n {formatCurrency(currentValue)}\n </p>\n </div>\n <div>\n <p className=\"text-text-secondary\">Total Return</p>\n <div className={cn('font-medium', getReturnColor(totalReturns))}>\n <div className=\"flex items-center gap-1\">\n {totalReturns > 0 && <ArrowUpRight className=\"h-3 w-3\" />}\n {totalReturns < 0 && <ArrowDownRight className=\"h-3 w-3\" />}\n {formatCurrency(totalReturns)}\n </div>\n <div className=\"text-sm\">{returnPercentage.toFixed(1)}%</div>\n </div>\n </div>\n <div>\n <p className=\"text-text-secondary\">Risk Level</p>\n <div className=\"mt-1\">\n <StatusBadge\n label={`${investment.riskLevel} risk`}\n variant={riskBadgeVariant(investment.riskLevel)}\n dot\n />\n </div>\n </div>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-5 text-xs text-text-secondary\">\n <span className=\"flex items-center gap-1\">\n <TrendingUp className=\"h-3 w-3\" />\n Start: {formatDateSafe(investment.startDate)}\n </span>\n <span className=\"flex items-center gap-1\">\n <Target className=\"h-3 w-3\" />\n Type: {investment.investmentType.replace('_', ' ')}\n </span>\n <span className=\"flex items-center gap-1\">\n <Calendar className=\"h-3 w-3\" />\n Returns: {returnsCount} payments\n </span>\n </div>\n </div>\n </div>\n </div>\n\n <div className=\"flex shrink-0 gap-2\">\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(`../investments/${investment.id}`);\n }}\n className=\"inline-flex items-center gap-1 rounded-md border border-border-subtle px-3 py-1.5 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <Eye className=\"h-4 w-4\" />\n View Details\n </button>\n </div>\n </div>\n </div>\n );\n })}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={investments.length >= pagination.pageSize}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<PieChart className=\"h-12 w-12\" />}\n title=\"No investments found\"\n description=\"Try adjusting your search criteria or start a new investment.\"\n action={\n <button\n onClick={openCreate}\n className=\"inline-flex items-center gap-2 rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Plus className=\"h-4 w-4\" />\n New Investment\n </button>\n }\n />\n )}\n </div>\n\n {/* Portfolio Allocation — real value split by investment type */}\n {allocation.rows.length > 0 && (\n <aside className=\"xl:col-span-1\">\n <ChartCard title=\"Portfolio Allocation\" description=\"Current value by investment type\">\n <div className=\"relative h-52 w-full\">\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <RePieChart>\n <Pie\n data={allocation.rows}\n dataKey=\"value\"\n nameKey=\"label\"\n innerRadius={56}\n outerRadius={82}\n paddingAngle={2}\n stroke=\"var(--color-bg-surface)\"\n strokeWidth={2}\n >\n {allocation.rows.map((entry) => (\n <Cell key={entry.type} fill={entry.color} />\n ))}\n </Pie>\n <Tooltip\n contentStyle={tooltipContentStyle}\n formatter={(value: number, _n, item) => [formatCurrency(value), item?.payload?.label]}\n />\n </RePieChart>\n </ResponsiveContainer>\n <div className=\"pointer-events-none absolute inset-0 flex flex-col items-center justify-center\">\n <span className=\"text-xs text-text-secondary\">Total value</span>\n <span className=\"text-lg font-bold text-text-primary\">{formatCurrency(allocation.total)}</span>\n </div>\n </div>\n <ul className=\"mt-4 space-y-2.5\">\n {allocation.rows.map((entry) => (\n <li key={entry.type} className=\"flex items-center justify-between text-sm\">\n <span className=\"flex items-center gap-2\">\n <span className=\"h-2.5 w-2.5 rounded-full\" style={{ background: entry.color }} />\n <span className=\"text-text-primary\">{entry.label}</span>\n </span>\n <span className=\"font-medium text-text-secondary\">{formatCurrency(entry.value)}</span>\n </li>\n ))}\n </ul>\n </ChartCard>\n </aside>\n )}\n </div>\n\n {/* Create Investment dialog */}\n <ResponsiveDialog open={createOpen} onOpenChange={setCreateOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-md\">\n <form onSubmit={handleCreate}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New investment</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Register a new holding against one of your properties.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Property *</label>\n <select\n required\n value={propertyId}\n onChange={(e) => setPropertyId(e.target.value)}\n className={inputClass}\n >\n <option value=\"\" disabled>\n {properties.length > 0 ? 'Select a property' : 'No properties available'}\n </option>\n {properties.map((property) => (\n <option key={property.id} value={property.id}>\n {property.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Title *</label>\n <input\n type=\"text\"\n required\n placeholder=\"e.g. Riverside Villa fractional stake\"\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n className={inputClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Type</label>\n <select\n value={investmentType}\n onChange={(e) => setInvestmentType(e.target.value as InvestmentType)}\n className={inputClass}\n >\n {investmentTypeOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Status</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as InvestmentStatus)}\n className={inputClass}\n >\n {statusOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Risk level</label>\n <select\n value={riskLevel}\n onChange={(e) => setRiskLevel(e.target.value as 'low' | 'medium' | 'high')}\n className={inputClass}\n >\n {riskOptions.map((option) => (\n <option key={option.value} value={option.value}>\n {option.label}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Total value (USD) *</label>\n <input\n type=\"number\"\n required\n min={1}\n step=\"any\"\n placeholder=\"0\"\n value={totalValue}\n onChange={(e) => setTotalValue(e.target.value)}\n className={inputClass}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Start date</label>\n <input\n type=\"date\"\n value={startDate}\n onChange={(e) => setStartDate(e.target.value)}\n className={inputClass}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Maturity date</label>\n <input\n type=\"date\"\n value={maturityDate}\n onChange={(e) => setMaturityDate(e.target.value)}\n className={inputClass}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setCreateOpen(false)}>\n Cancel\n </Button>\n <Button type=\"submit\" disabled={creating || !propertyId || !title.trim() || !totalValue}>\n {creating ? 'Creating…' : 'Create investment'}\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":"LegalPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/legal/LegalPage.tsx"],"names":[],"mappings":"AAiLA,wBAAgB,SAAS,gCAoHxB"}
1
+ {"version":3,"file":"LegalPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/legal/LegalPage.tsx"],"names":[],"mappings":"AAkLA,wBAAgB,SAAS,gCAqHxB"}