@burdenoff/microfe-housingvista 2026.626.2 → 2026.703.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/dist/housingvista/HousingVistaRoot.js +60 -59
  2. package/dist/housingvista/HousingVistaRoot.js.map +1 -1
  3. package/dist/housingvista/HousingVistaRoutes.js +25 -21
  4. package/dist/housingvista/HousingVistaRoutes.js.map +1 -1
  5. package/dist/housingvista/components/DataTable.js +1 -1
  6. package/dist/housingvista/components/DataTable.js.map +1 -1
  7. package/dist/housingvista/components/EmptyState.js.map +1 -1
  8. package/dist/housingvista/components/ErrorBoundary.js +3 -3
  9. package/dist/housingvista/components/ErrorBoundary.js.map +1 -1
  10. package/dist/housingvista/components/LoadingSkeleton.js +76 -1
  11. package/dist/housingvista/components/LoadingSkeleton.js.map +1 -0
  12. package/dist/housingvista/components/PageLayout.js.map +1 -1
  13. package/dist/housingvista/components/PropertyCard.js +49 -50
  14. package/dist/housingvista/components/PropertyCard.js.map +1 -1
  15. package/dist/housingvista/components/StatCard.js +3 -3
  16. package/dist/housingvista/components/StatCard.js.map +1 -1
  17. package/dist/housingvista/components/StatusBadge.js +8 -8
  18. package/dist/housingvista/components/StatusBadge.js.map +1 -1
  19. package/dist/housingvista/components/index.js +0 -2
  20. package/dist/housingvista/hooks/index.js +670 -198
  21. package/dist/housingvista/hooks/index.js.map +1 -1
  22. package/dist/housingvista/lib/toast.js +36 -0
  23. package/dist/housingvista/lib/toast.js.map +1 -0
  24. package/dist/housingvista/pages/HomePage.js +8 -8
  25. package/dist/housingvista/pages/HomePage.js.map +1 -1
  26. package/dist/housingvista/pages/amc/AMCManagementPage.js +254 -78
  27. package/dist/housingvista/pages/amc/AMCManagementPage.js.map +1 -1
  28. package/dist/housingvista/pages/analytics/AnalyticsPage.js +192 -161
  29. package/dist/housingvista/pages/analytics/AnalyticsPage.js.map +1 -1
  30. package/dist/housingvista/pages/assets/AssetManagementPage.js +4 -4
  31. package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
  32. package/dist/housingvista/pages/chat/ChatPage.js +17 -209
  33. package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
  34. package/dist/housingvista/pages/finance/HomeLoansPage.js +11 -11
  35. package/dist/housingvista/pages/finance/HomeLoansPage.js.map +1 -1
  36. package/dist/housingvista/pages/investments/InvestmentDetailPage.js +243 -205
  37. package/dist/housingvista/pages/investments/InvestmentDetailPage.js.map +1 -1
  38. package/dist/housingvista/pages/investments/InvestmentsPage.js +348 -114
  39. package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
  40. package/dist/housingvista/pages/legal/LegalPage.js +8 -8
  41. package/dist/housingvista/pages/legal/LegalPage.js.map +1 -1
  42. package/dist/housingvista/pages/market/AreaInsightsPage.js +81 -84
  43. package/dist/housingvista/pages/market/AreaInsightsPage.js.map +1 -1
  44. package/dist/housingvista/pages/market/MarketAnalyticsPage.js +83 -85
  45. package/dist/housingvista/pages/market/MarketAnalyticsPage.js.map +1 -1
  46. package/dist/housingvista/pages/marketplace/MarketplacePage.js +6 -6
  47. package/dist/housingvista/pages/marketplace/MarketplacePage.js.map +1 -1
  48. package/dist/housingvista/pages/notifications/NotificationsPage.js +19 -133
  49. package/dist/housingvista/pages/notifications/NotificationsPage.js.map +1 -1
  50. package/dist/housingvista/pages/properties/AddPropertyPage.js +279 -243
  51. package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
  52. package/dist/housingvista/pages/properties/PropertiesPage.js +216 -165
  53. package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
  54. package/dist/housingvista/pages/properties/PropertyDetailPage.js +619 -424
  55. package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
  56. package/dist/housingvista/pages/rental/RentalManagementPage.js +493 -130
  57. package/dist/housingvista/pages/rental/RentalManagementPage.js.map +1 -1
  58. package/dist/housingvista/pages/settings/ProfilePage.js +102 -102
  59. package/dist/housingvista/pages/settings/ProfilePage.js.map +1 -1
  60. package/dist/housingvista/pages/settings/SettingsPage.js +99 -139
  61. package/dist/housingvista/pages/settings/SettingsPage.js.map +1 -1
  62. package/dist/housingvista/pages/shortlist/ShortlistPage.js +63 -0
  63. package/dist/housingvista/pages/shortlist/ShortlistPage.js.map +1 -0
  64. package/dist/housingvista/pages/transactions/TransactionDetailPage.js +140 -185
  65. package/dist/housingvista/pages/transactions/TransactionDetailPage.js.map +1 -1
  66. package/dist/housingvista/pages/transactions/TransactionsPage.js +269 -110
  67. package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
  68. package/dist/housingvista/pages/verification/VerificationPage.js +195 -116
  69. package/dist/housingvista/pages/verification/VerificationPage.js.map +1 -1
  70. package/dist/node_modules/sonner/dist/index.js +163 -0
  71. package/dist/node_modules/sonner/dist/index.js.map +1 -0
  72. package/package.json +3 -3
  73. package/dist/housingvista/components/Modal.js +0 -3
  74. package/dist/housingvista/components/Toast.js +0 -3
@@ -6,13 +6,18 @@ import { StatusBadge as o } from "../../components/StatusBadge.js";
6
6
  import { EmptyState as s } from "../../components/EmptyState.js";
7
7
  import { FilterBar as c } from "../../components/FilterBar.js";
8
8
  import "../../components/index.js";
9
- import { useAMCContracts as l } from "../../hooks/index.js";
10
- import { useMemo as u, useState as d } from "react";
11
- import { AlertTriangle as f, Calendar as p, Clock as m, DollarSign as h, Download as g, Plus as _, RotateCcw as v, Shield as y, Wrench as b } from "lucide-react";
12
- import { useNavigate as x } from "react-router-dom";
13
- import { jsx as S, jsxs as C } from "react/jsx-runtime";
14
- import { EmphasisPanel as w, NextSteps as T } from "@burdenoff/fe-libs/ui";
9
+ import { useAMCContracts as l, useCreateAmcContract as u } from "../../hooks/index.js";
10
+ import { notify as d } from "../../lib/toast.js";
11
+ import { useMemo as f, useState as p } from "react";
12
+ import { AlertTriangle as m, Calendar as ee, Clock as te, DollarSign as ne, Download as re, Plus as h, RotateCcw as g, Shield as _, Wrench as ie } from "lucide-react";
13
+ import { useNavigate as ae } from "react-router-dom";
14
+ import { jsx as v, jsxs as y } from "react/jsx-runtime";
15
+ import { Button as b, EmphasisPanel as oe, NextSteps as se, ResponsiveDialog as ce, ResponsiveDialogContent as le, ResponsiveDialogDescription as ue, ResponsiveDialogFooter as x, ResponsiveDialogHeader as S, ResponsiveDialogTitle as C } from "@burdenoff/fe-libs/ui";
15
16
  //#region src/housingvista/pages/amc/AMCManagementPage.tsx
17
+ var w = "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)]";
18
+ function T(e) {
19
+ return e ? new Date(e).toISOString() : "";
20
+ }
16
21
  function E(e) {
17
22
  switch (e) {
18
23
  case "active": return "success";
@@ -23,11 +28,41 @@ function E(e) {
23
28
  }
24
29
  }
25
30
  function D() {
26
- let D = x(), { data: O } = l(), [k, A] = d(""), j = u(() => {
31
+ let D = ae(), { data: O } = l(), [k, A] = p(""), { createAmcContract: de, loading: j } = u(), [fe, M] = p(!1), [N, P] = p(""), [F, I] = p(""), [L, R] = p(""), [z, B] = p(""), [V, H] = p(""), [U, W] = p(""), [G, K] = p("active"), [q, J] = p(""), Y = () => {
32
+ P(""), I(""), R(""), B(""), H(""), W(""), K("active"), J("");
33
+ }, X = () => {
34
+ Y(), M(!0);
35
+ }, pe = async (e) => {
36
+ e.preventDefault();
37
+ let t = Number(z);
38
+ if (!N.trim() || !F.trim() || !L.trim()) {
39
+ d.warning("Missing details", "Property, package and provider are required.");
40
+ return;
41
+ }
42
+ if (!Number.isFinite(t) || t <= 0) {
43
+ d.warning("Enter a valid monthly cost");
44
+ return;
45
+ }
46
+ let n = q.split(",").map((e) => e.trim()).filter((e) => e.length > 0);
47
+ try {
48
+ await de({
49
+ propertyTitle: N.trim(),
50
+ packageName: F.trim(),
51
+ providerName: L.trim(),
52
+ monthlyCost: t,
53
+ startDate: T(V),
54
+ endDate: T(U),
55
+ status: G,
56
+ servicesIncluded: n.length > 0 ? n : void 0
57
+ }), d.success("Contract created", `${F.trim()} added for ${N.trim()}.`), M(!1), Y();
58
+ } catch (e) {
59
+ d.error("Could not create contract", e.message);
60
+ }
61
+ }, Z = f(() => {
27
62
  if (!k) return O;
28
63
  let e = k.toLowerCase();
29
64
  return O.filter((t) => t.propertyTitle.toLowerCase().includes(e) || t.providerName.toLowerCase().includes(e) || t.packageName.toLowerCase().includes(e));
30
- }, [O, k]), M = u(() => ({
65
+ }, [O, k]), Q = f(() => ({
31
66
  activeContracts: O.filter((e) => e.status === "active" || e.status === "expiring_soon").length,
32
67
  pendingRenewals: O.filter((e) => e.status === "expiring_soon").length,
33
68
  totalMonthlySpent: O.filter((e) => e.status === "active" || e.status === "expiring_soon").reduce((e, t) => e + t.monthlyCost, 0),
@@ -36,54 +71,56 @@ function D() {
36
71
  let t = new Date(e.nextServiceDate), n = /* @__PURE__ */ new Date(), r = (t.getTime() - n.getTime()) / (1e3 * 60 * 60 * 24);
37
72
  return r >= 0 && r <= 30;
38
73
  }).length
39
- }), [O]), N = u(() => O.filter((e) => e.nextServiceDate && (e.status === "active" || e.status === "expiring_soon")).sort((e, t) => new Date(e.nextServiceDate).getTime() - new Date(t.nextServiceDate).getTime()), [O]);
40
- return /* @__PURE__ */ C(r, {
74
+ }), [O]), $ = f(() => O.filter((e) => e.nextServiceDate && (e.status === "active" || e.status === "expiring_soon")).sort((e, t) => new Date(e.nextServiceDate).getTime() - new Date(t.nextServiceDate).getTime()), [O]);
75
+ return /* @__PURE__ */ y(r, {
41
76
  title: "AMC Management",
42
77
  description: "Manage Annual Maintenance Contracts and service packages",
43
78
  purpose: "Keep your properties maintained without surprises. Track every Annual Maintenance Contract, see what each covers and costs, get ahead of renewals, and know which services are due in the next 30 days so nothing slips.",
44
- actions: /* @__PURE__ */ C("div", {
79
+ actions: /* @__PURE__ */ y("div", {
45
80
  className: "flex items-center gap-2",
46
- children: [/* @__PURE__ */ C("button", {
81
+ children: [/* @__PURE__ */ y("button", {
47
82
  className: "inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken",
48
- children: [/* @__PURE__ */ S(g, { className: "h-4 w-4" }), "Export"]
49
- }), /* @__PURE__ */ C("button", {
50
- className: "inline-flex items-center gap-2 rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90",
51
- children: [/* @__PURE__ */ S(_, { className: "h-4 w-4" }), "New Contract"]
83
+ children: [/* @__PURE__ */ v(re, { className: "h-4 w-4" }), "Export"]
84
+ }), /* @__PURE__ */ y(b, {
85
+ type: "button",
86
+ onClick: X,
87
+ className: "gap-2",
88
+ children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), "New Contract"]
52
89
  })]
53
90
  }),
54
91
  children: [
55
- /* @__PURE__ */ S(w, {
92
+ /* @__PURE__ */ v(oe, {
56
93
  className: "p-4",
57
- children: /* @__PURE__ */ C("div", {
94
+ children: /* @__PURE__ */ y("div", {
58
95
  className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
59
96
  children: [
60
- /* @__PURE__ */ S(i, {
97
+ /* @__PURE__ */ v(i, {
61
98
  label: "Active Contracts",
62
- value: M.activeContracts,
63
- icon: /* @__PURE__ */ S(y, { className: "h-4 w-4" })
99
+ value: Q.activeContracts,
100
+ icon: /* @__PURE__ */ v(_, { className: "h-4 w-4" })
64
101
  }),
65
- /* @__PURE__ */ S(i, {
102
+ /* @__PURE__ */ v(i, {
66
103
  label: "Pending Renewals",
67
- value: M.pendingRenewals,
68
- icon: /* @__PURE__ */ S(v, { className: "h-4 w-4" }),
69
- trend: M.pendingRenewals > 0 ? "up" : "stable",
70
- change: M.pendingRenewals > 0 ? M.pendingRenewals : 0
104
+ value: Q.pendingRenewals,
105
+ icon: /* @__PURE__ */ v(g, { className: "h-4 w-4" }),
106
+ trend: Q.pendingRenewals > 0 ? "up" : "stable",
107
+ change: Q.pendingRenewals > 0 ? Q.pendingRenewals : 0
71
108
  }),
72
- /* @__PURE__ */ S(i, {
109
+ /* @__PURE__ */ v(i, {
73
110
  label: "Total Monthly Spent",
74
- value: M.totalMonthlySpent,
111
+ value: Q.totalMonthlySpent,
75
112
  prefix: "$",
76
- icon: /* @__PURE__ */ S(h, { className: "h-4 w-4" })
113
+ icon: /* @__PURE__ */ v(ne, { className: "h-4 w-4" })
77
114
  }),
78
- /* @__PURE__ */ S(i, {
115
+ /* @__PURE__ */ v(i, {
79
116
  label: "Upcoming Services",
80
- value: M.upcomingServices,
81
- icon: /* @__PURE__ */ S(p, { className: "h-4 w-4" })
117
+ value: Q.upcomingServices,
118
+ icon: /* @__PURE__ */ v(ee, { className: "h-4 w-4" })
82
119
  })
83
120
  ]
84
121
  })
85
122
  }),
86
- /* @__PURE__ */ S(T, {
123
+ /* @__PURE__ */ v(se, {
87
124
  storageKey: "housingvista-amc",
88
125
  steps: [
89
126
  {
@@ -109,33 +146,33 @@ function D() {
109
146
  }
110
147
  ]
111
148
  }),
112
- /* @__PURE__ */ C("div", {
149
+ /* @__PURE__ */ y("div", {
113
150
  className: "rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm",
114
- children: [/* @__PURE__ */ S("h3", {
151
+ children: [/* @__PURE__ */ v("h3", {
115
152
  className: "mb-4 text-lg font-semibold text-text-primary",
116
153
  children: "Upcoming Service Schedule"
117
- }), N.length === 0 ? /* @__PURE__ */ S(s, {
154
+ }), $.length === 0 ? /* @__PURE__ */ v(s, {
118
155
  illustration: "empty-generic",
119
156
  title: "No services scheduled",
120
157
  description: "Once your active contracts have upcoming service dates, they'll be listed here in order of priority.",
121
158
  className: "border-0 bg-transparent p-6"
122
- }) : /* @__PURE__ */ S("div", {
159
+ }) : /* @__PURE__ */ v("div", {
123
160
  className: "space-y-3",
124
- children: N.map((t) => {
161
+ children: $.map((t) => {
125
162
  let r = new Date(t.nextServiceDate), i = /* @__PURE__ */ new Date(), a = Math.ceil((r.getTime() - i.getTime()) / (1e3 * 60 * 60 * 24)), s = a <= 7, c = a < 0;
126
- return /* @__PURE__ */ C("div", {
163
+ return /* @__PURE__ */ y("div", {
127
164
  className: "flex flex-col gap-3 rounded-lg bg-bg-sunken/50 p-4 sm:flex-row sm:items-center sm:justify-between",
128
- children: [/* @__PURE__ */ C("div", {
165
+ children: [/* @__PURE__ */ y("div", {
129
166
  className: "flex items-start gap-3",
130
- children: [/* @__PURE__ */ S("div", {
131
- className: e("rounded-lg p-2", c ? "bg-red-100 dark:bg-red-900/30" : s ? "bg-amber-100 dark:bg-amber-900/30" : "bg-blue-100 dark:bg-blue-900/30"),
132
- children: c ? /* @__PURE__ */ S(f, { className: "h-4 w-4 text-red-600 dark:text-red-400" }) : s ? /* @__PURE__ */ S(m, { className: "h-4 w-4 text-amber-600 dark:text-amber-400" }) : /* @__PURE__ */ S(b, { className: "h-4 w-4 text-blue-600 dark:text-blue-400" })
133
- }), /* @__PURE__ */ C("div", { children: [
134
- /* @__PURE__ */ S("p", {
167
+ children: [/* @__PURE__ */ v("div", {
168
+ className: e("rounded-lg p-2", c ? "bg-status-error-bg-subtle" : s ? "bg-status-warning-bg-subtle" : "bg-status-info-bg-subtle"),
169
+ children: c ? /* @__PURE__ */ v(m, { className: "h-4 w-4 text-status-error-text" }) : s ? /* @__PURE__ */ v(te, { className: "h-4 w-4 text-status-warning-text" }) : /* @__PURE__ */ v(ie, { className: "h-4 w-4 text-status-info-text" })
170
+ }), /* @__PURE__ */ y("div", { children: [
171
+ /* @__PURE__ */ v("p", {
135
172
  className: "font-medium text-text-primary",
136
173
  children: t.propertyTitle
137
174
  }),
138
- /* @__PURE__ */ C("p", {
175
+ /* @__PURE__ */ y("p", {
139
176
  className: "text-sm text-text-secondary",
140
177
  children: [
141
178
  t.packageName,
@@ -143,12 +180,12 @@ function D() {
143
180
  t.providerName
144
181
  ]
145
182
  }),
146
- /* @__PURE__ */ C("div", {
183
+ /* @__PURE__ */ y("div", {
147
184
  className: "mt-1 flex flex-wrap gap-1",
148
- children: [t.servicesIncluded.slice(0, 3).map((e, t) => /* @__PURE__ */ S("span", {
185
+ children: [t.servicesIncluded.slice(0, 3).map((e, t) => /* @__PURE__ */ v("span", {
149
186
  className: "inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
150
187
  children: e
151
- }, t)), t.servicesIncluded.length > 3 && /* @__PURE__ */ C("span", {
188
+ }, t)), t.servicesIncluded.length > 3 && /* @__PURE__ */ y("span", {
152
189
  className: "inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
153
190
  children: [
154
191
  "+",
@@ -158,18 +195,18 @@ function D() {
158
195
  })]
159
196
  })
160
197
  ] })]
161
- }), /* @__PURE__ */ C("div", {
198
+ }), /* @__PURE__ */ y("div", {
162
199
  className: "flex items-center gap-3",
163
- children: [/* @__PURE__ */ C("div", {
200
+ children: [/* @__PURE__ */ y("div", {
164
201
  className: "text-right",
165
- children: [/* @__PURE__ */ S("p", {
202
+ children: [/* @__PURE__ */ v("p", {
166
203
  className: "text-sm font-medium text-text-primary",
167
204
  children: n(t.nextServiceDate)
168
- }), /* @__PURE__ */ S("p", {
169
- className: e("text-xs", c ? "text-red-600 dark:text-red-400" : s ? "text-amber-600 dark:text-amber-400" : "text-text-secondary"),
205
+ }), /* @__PURE__ */ v("p", {
206
+ className: e("text-xs", c ? "text-status-error-text" : s ? "text-status-warning-text" : "text-text-secondary"),
170
207
  children: c ? `${Math.abs(a)} days overdue` : a === 0 ? "Today" : `In ${a} days`
171
208
  })]
172
- }), /* @__PURE__ */ S(o, {
209
+ }), /* @__PURE__ */ v(o, {
173
210
  label: t.status.replace("_", " "),
174
211
  variant: E(t.status)
175
212
  })]
@@ -178,27 +215,27 @@ function D() {
178
215
  })
179
216
  })]
180
217
  }),
181
- /* @__PURE__ */ C("div", { children: [
182
- /* @__PURE__ */ S("h2", {
218
+ /* @__PURE__ */ y("div", { children: [
219
+ /* @__PURE__ */ v("h2", {
183
220
  className: "mb-4 text-lg font-semibold text-text-primary",
184
221
  children: "All Contracts"
185
222
  }),
186
- /* @__PURE__ */ S(c, {
223
+ /* @__PURE__ */ v(c, {
187
224
  searchValue: k,
188
225
  onSearchChange: A,
189
226
  searchPlaceholder: "Search contracts, providers, properties..."
190
227
  }),
191
- /* @__PURE__ */ S("div", {
228
+ /* @__PURE__ */ v("div", {
192
229
  className: "mt-4",
193
- children: j.length > 0 ? /* @__PURE__ */ S(a, {
230
+ children: Z.length > 0 ? /* @__PURE__ */ v(a, {
194
231
  columns: [
195
232
  {
196
233
  key: "packageName",
197
234
  header: "Contract",
198
- render: (e) => /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("div", {
235
+ render: (e) => /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("div", {
199
236
  className: "font-medium text-text-primary",
200
237
  children: e.packageName
201
- }), /* @__PURE__ */ S("div", {
238
+ }), /* @__PURE__ */ v("div", {
202
239
  className: "text-xs text-text-secondary",
203
240
  children: e.propertyTitle
204
241
  })] })
@@ -206,7 +243,7 @@ function D() {
206
243
  {
207
244
  key: "providerName",
208
245
  header: "Provider",
209
- render: (e) => /* @__PURE__ */ S("span", {
246
+ render: (e) => /* @__PURE__ */ v("span", {
210
247
  className: "text-sm text-text-primary",
211
248
  children: e.providerName
212
249
  })
@@ -214,12 +251,12 @@ function D() {
214
251
  {
215
252
  key: "servicesIncluded",
216
253
  header: "Coverage",
217
- render: (e) => /* @__PURE__ */ C("div", {
254
+ render: (e) => /* @__PURE__ */ y("div", {
218
255
  className: "max-w-[200px]",
219
- children: [/* @__PURE__ */ C("span", {
256
+ children: [/* @__PURE__ */ y("span", {
220
257
  className: "text-sm text-text-primary",
221
258
  children: [e.servicesIncluded.length, " services"]
222
- }), /* @__PURE__ */ C("p", {
259
+ }), /* @__PURE__ */ y("p", {
223
260
  className: "truncate text-xs text-text-secondary",
224
261
  children: [e.servicesIncluded.slice(0, 2).join(", "), e.servicesIncluded.length > 2 && ` +${e.servicesIncluded.length - 2} more`]
225
262
  })]
@@ -228,10 +265,10 @@ function D() {
228
265
  {
229
266
  key: "monthlyCost",
230
267
  header: "Cost",
231
- render: (e) => /* @__PURE__ */ C("div", { children: [/* @__PURE__ */ S("span", {
268
+ render: (e) => /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("span", {
232
269
  className: "font-medium text-text-primary",
233
270
  children: t(e.monthlyCost)
234
- }), /* @__PURE__ */ S("span", {
271
+ }), /* @__PURE__ */ v("span", {
235
272
  className: "text-xs text-text-secondary",
236
273
  children: "/mo"
237
274
  })] })
@@ -239,7 +276,7 @@ function D() {
239
276
  {
240
277
  key: "startDate",
241
278
  header: "Start",
242
- render: (e) => /* @__PURE__ */ S("span", {
279
+ render: (e) => /* @__PURE__ */ v("span", {
243
280
  className: "text-sm text-text-primary",
244
281
  children: n(e.startDate)
245
282
  })
@@ -247,7 +284,7 @@ function D() {
247
284
  {
248
285
  key: "endDate",
249
286
  header: "End",
250
- render: (e) => /* @__PURE__ */ S("span", {
287
+ render: (e) => /* @__PURE__ */ v("span", {
251
288
  className: "text-sm text-text-primary",
252
289
  children: n(e.endDate)
253
290
  })
@@ -255,28 +292,167 @@ function D() {
255
292
  {
256
293
  key: "status",
257
294
  header: "Status",
258
- render: (e) => /* @__PURE__ */ S(o, {
295
+ render: (e) => /* @__PURE__ */ v(o, {
259
296
  label: e.status.replace("_", " "),
260
297
  variant: E(e.status),
261
298
  dot: !0
262
299
  })
263
300
  }
264
301
  ],
265
- data: j,
302
+ data: Z,
266
303
  keyField: "id",
267
304
  pageSize: 10
268
- }) : /* @__PURE__ */ S(s, {
305
+ }) : /* @__PURE__ */ v(s, {
269
306
  illustration: "empty-search",
270
- icon: /* @__PURE__ */ S(y, { className: "h-12 w-12" }),
307
+ icon: /* @__PURE__ */ v(_, { className: "h-12 w-12" }),
271
308
  title: "No contracts found",
272
309
  description: "Try adjusting your search criteria or create a new contract.",
273
- action: /* @__PURE__ */ C("button", {
274
- className: "inline-flex items-center gap-2 rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90",
275
- children: [/* @__PURE__ */ S(_, { className: "h-4 w-4" }), "New Contract"]
310
+ action: /* @__PURE__ */ y(b, {
311
+ type: "button",
312
+ onClick: X,
313
+ className: "gap-2",
314
+ children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), "New Contract"]
276
315
  })
277
316
  })
278
317
  })
279
- ] })
318
+ ] }),
319
+ /* @__PURE__ */ v(ce, {
320
+ open: fe,
321
+ onOpenChange: M,
322
+ children: /* @__PURE__ */ v(le, {
323
+ className: "sm:max-w-lg",
324
+ children: /* @__PURE__ */ y("form", {
325
+ onSubmit: pe,
326
+ children: [
327
+ /* @__PURE__ */ y(S, { children: [/* @__PURE__ */ v(C, { children: "New maintenance contract" }), /* @__PURE__ */ v(ue, { children: "Set up an Annual Maintenance Contract to track coverage, cost and renewal dates." })] }),
328
+ /* @__PURE__ */ y("div", {
329
+ className: "space-y-3 py-2",
330
+ children: [
331
+ /* @__PURE__ */ y("div", {
332
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
333
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
334
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
335
+ children: "Property *"
336
+ }), /* @__PURE__ */ v("input", {
337
+ type: "text",
338
+ required: !0,
339
+ placeholder: "e.g. Maple Court",
340
+ value: N,
341
+ onChange: (e) => P(e.target.value),
342
+ className: w
343
+ })] }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
344
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
345
+ children: "Package *"
346
+ }), /* @__PURE__ */ v("input", {
347
+ type: "text",
348
+ required: !0,
349
+ placeholder: "e.g. Premium Care",
350
+ value: F,
351
+ onChange: (e) => I(e.target.value),
352
+ className: w
353
+ })] })]
354
+ }),
355
+ /* @__PURE__ */ y("div", {
356
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-2",
357
+ children: [/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
358
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
359
+ children: "Provider *"
360
+ }), /* @__PURE__ */ v("input", {
361
+ type: "text",
362
+ required: !0,
363
+ placeholder: "Service company",
364
+ value: L,
365
+ onChange: (e) => R(e.target.value),
366
+ className: w
367
+ })] }), /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
368
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
369
+ children: "Monthly cost *"
370
+ }), /* @__PURE__ */ v("input", {
371
+ type: "number",
372
+ required: !0,
373
+ min: 0,
374
+ step: "0.01",
375
+ placeholder: "0.00",
376
+ value: z,
377
+ onChange: (e) => B(e.target.value),
378
+ className: w
379
+ })] })]
380
+ }),
381
+ /* @__PURE__ */ y("div", {
382
+ className: "grid grid-cols-1 gap-3 sm:grid-cols-3",
383
+ children: [
384
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
385
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
386
+ children: "Start date"
387
+ }), /* @__PURE__ */ v("input", {
388
+ type: "date",
389
+ value: V,
390
+ onChange: (e) => H(e.target.value),
391
+ className: w
392
+ })] }),
393
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
394
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
395
+ children: "End date"
396
+ }), /* @__PURE__ */ v("input", {
397
+ type: "date",
398
+ value: U,
399
+ onChange: (e) => W(e.target.value),
400
+ className: w
401
+ })] }),
402
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
403
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
404
+ children: "Status"
405
+ }), /* @__PURE__ */ y("select", {
406
+ value: G,
407
+ onChange: (e) => K(e.target.value),
408
+ className: w,
409
+ children: [
410
+ /* @__PURE__ */ v("option", {
411
+ value: "active",
412
+ children: "Active"
413
+ }),
414
+ /* @__PURE__ */ v("option", {
415
+ value: "expiring_soon",
416
+ children: "Expiring soon"
417
+ }),
418
+ /* @__PURE__ */ v("option", {
419
+ value: "expired",
420
+ children: "Expired"
421
+ }),
422
+ /* @__PURE__ */ v("option", {
423
+ value: "cancelled",
424
+ children: "Cancelled"
425
+ })
426
+ ]
427
+ })] })
428
+ ]
429
+ }),
430
+ /* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
431
+ className: "mb-1.5 block text-sm font-medium text-text-primary",
432
+ children: "Services included"
433
+ }), /* @__PURE__ */ v("input", {
434
+ type: "text",
435
+ placeholder: "Comma-separated, e.g. Plumbing, Electrical, HVAC",
436
+ value: q,
437
+ onChange: (e) => J(e.target.value),
438
+ className: w
439
+ })] })
440
+ ]
441
+ }),
442
+ /* @__PURE__ */ y(x, { children: [/* @__PURE__ */ v(b, {
443
+ type: "button",
444
+ variant: "outline",
445
+ onClick: () => M(!1),
446
+ children: "Cancel"
447
+ }), /* @__PURE__ */ v(b, {
448
+ type: "submit",
449
+ disabled: j,
450
+ children: j ? "Saving…" : "Create contract"
451
+ })] })
452
+ ]
453
+ })
454
+ })
455
+ })
280
456
  ]
281
457
  });
282
458
  }
@@ -1 +1 @@
1
- {"version":3,"file":"AMCManagementPage.js","names":[],"sources":["../../../../src/housingvista/pages/amc/AMCManagementPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Shield,\n FileText,\n DollarSign,\n Calendar,\n Plus,\n Download,\n CheckCircle,\n Clock,\n AlertTriangle,\n Wrench,\n RotateCcw,\n Eye,\n} from 'lucide-react';\nimport { EmphasisPanel, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components';\nimport { StatCard } from '../../components';\nimport { DataTable, type Column } from '../../components';\nimport { StatusBadge } from '../../components';\nimport { FilterBar } from '../../components';\nimport { EmptyState } from '../../components';\nimport { useAMCContracts } from '../../hooks';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport type { AMCContract } from '../../types';\n\nfunction getStatusVariant(status: AMCContract['status']): 'success' | 'warning' | 'error' | 'muted' {\n switch (status) {\n case 'active':\n return 'success';\n case 'expiring_soon':\n return 'warning';\n case 'expired':\n return 'error';\n case 'cancelled':\n return 'muted';\n default:\n return 'muted';\n }\n}\n\nexport function AMCManagementPage() {\n const navigate = useNavigate();\n const { data: amcContracts } = useAMCContracts();\n const [search, setSearch] = useState('');\n\n const filtered = useMemo(() => {\n if (!search) return amcContracts;\n const q = search.toLowerCase();\n return amcContracts.filter(\n (c) =>\n c.propertyTitle.toLowerCase().includes(q) ||\n c.providerName.toLowerCase().includes(q) ||\n c.packageName.toLowerCase().includes(q)\n );\n }, [amcContracts, search]);\n\n const stats = useMemo(() => {\n const activeContracts = amcContracts.filter((c) => c.status === 'active' || c.status === 'expiring_soon').length;\n const pendingRenewals = amcContracts.filter((c) => c.status === 'expiring_soon').length;\n const totalMonthlySpent = amcContracts\n .filter((c) => c.status === 'active' || c.status === 'expiring_soon')\n .reduce((sum, c) => sum + c.monthlyCost, 0);\n const upcomingServices = amcContracts.filter((c) => {\n if (!c.nextServiceDate) return false;\n const serviceDate = new Date(c.nextServiceDate);\n const now = new Date();\n const daysUntil = (serviceDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);\n return daysUntil >= 0 && daysUntil <= 30;\n }).length;\n return { activeContracts, pendingRenewals, totalMonthlySpent, upcomingServices };\n }, [amcContracts]);\n\n const scheduledServices = useMemo(\n () =>\n amcContracts\n .filter((c) => c.nextServiceDate && (c.status === 'active' || c.status === 'expiring_soon'))\n .sort((a, b) => new Date(a.nextServiceDate).getTime() - new Date(b.nextServiceDate).getTime()),\n [amcContracts]\n );\n\n const contractColumns: Column<AMCContract>[] = [\n {\n key: 'packageName',\n header: 'Contract',\n render: (item) => (\n <div>\n <div className=\"font-medium text-text-primary\">{item.packageName}</div>\n <div className=\"text-xs text-text-secondary\">{item.propertyTitle}</div>\n </div>\n ),\n },\n {\n key: 'providerName',\n header: 'Provider',\n render: (item) => <span className=\"text-sm text-text-primary\">{item.providerName}</span>,\n },\n {\n key: 'servicesIncluded',\n header: 'Coverage',\n render: (item) => (\n <div className=\"max-w-[200px]\">\n <span className=\"text-sm text-text-primary\">{item.servicesIncluded.length} services</span>\n <p className=\"truncate text-xs text-text-secondary\">\n {item.servicesIncluded.slice(0, 2).join(', ')}\n {item.servicesIncluded.length > 2 && ` +${item.servicesIncluded.length - 2} more`}\n </p>\n </div>\n ),\n },\n {\n key: 'monthlyCost',\n header: 'Cost',\n render: (item) => (\n <div>\n <span className=\"font-medium text-text-primary\">{formatCurrency(item.monthlyCost)}</span>\n <span className=\"text-xs text-text-secondary\">/mo</span>\n </div>\n ),\n },\n {\n key: 'startDate',\n header: 'Start',\n render: (item) => <span className=\"text-sm text-text-primary\">{formatDate(item.startDate)}</span>,\n },\n {\n key: 'endDate',\n header: 'End',\n render: (item) => <span className=\"text-sm text-text-primary\">{formatDate(item.endDate)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (item) => (\n <StatusBadge label={item.status.replace('_', ' ')} variant={getStatusVariant(item.status)} dot />\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"AMC Management\"\n description=\"Manage Annual Maintenance Contracts and service packages\"\n purpose=\"Keep your properties maintained without surprises. Track every Annual Maintenance Contract, see what each covers and costs, get ahead of renewals, and know which services are due in the next 30 days so nothing slips.\"\n actions={\n <div className=\"flex items-center gap-2\">\n <button className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\">\n <Download className=\"h-4 w-4\" />\n Export\n </button>\n <button className=\"inline-flex items-center gap-2 rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90\">\n <Plus className=\"h-4 w-4\" />\n New Contract\n </button>\n </div>\n }\n >\n {/* 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 label=\"Active Contracts\" value={stats.activeContracts} icon={<Shield className=\"h-4 w-4\" />} />\n <StatCard\n label=\"Pending Renewals\"\n value={stats.pendingRenewals}\n icon={<RotateCcw className=\"h-4 w-4\" />}\n trend={stats.pendingRenewals > 0 ? 'up' : 'stable'}\n change={stats.pendingRenewals > 0 ? stats.pendingRenewals : 0}\n />\n <StatCard\n label=\"Total Monthly Spent\"\n value={stats.totalMonthlySpent}\n prefix=\"$\"\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n <StatCard label=\"Upcoming Services\" value={stats.upcomingServices} icon={<Calendar className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-amc\"\n steps={[\n {\n id: 'pick-property',\n label: 'Add coverage for a property',\n description: 'Choose a property to set up a new maintenance contract.',\n onClick: () => navigate('/properties'),\n },\n {\n id: 'compare-providers',\n label: 'Compare your providers',\n description: 'Search by provider name to weigh coverage and monthly cost.',\n onClick: () => {\n const firstProvider = amcContracts[0]?.providerName;\n if (firstProvider) setSearch(firstProvider);\n },\n },\n {\n id: 'check-legal',\n label: 'Review contract paperwork',\n description: 'Open the legal hub to manage the underlying documents.',\n onClick: () => navigate('/legal'),\n },\n ]}\n />\n\n {/* Service Schedule Section */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Upcoming Service Schedule</h3>\n {scheduledServices.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No services scheduled\"\n description=\"Once your active contracts have upcoming service dates, they'll be listed here in order of priority.\"\n className=\"border-0 bg-transparent p-6\"\n />\n ) : (\n <div className=\"space-y-3\">\n {scheduledServices\n .map((contract) => {\n const serviceDate = new Date(contract.nextServiceDate);\n const now = new Date();\n const daysUntil = Math.ceil((serviceDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));\n const isUrgent = daysUntil <= 7;\n const isPast = daysUntil < 0;\n\n return (\n <div\n key={contract.id}\n className=\"flex flex-col gap-3 rounded-lg bg-bg-sunken/50 p-4 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex items-start gap-3\">\n <div\n className={cn(\n 'rounded-lg p-2',\n isPast\n ? 'bg-red-100 dark:bg-red-900/30'\n : isUrgent\n ? 'bg-amber-100 dark:bg-amber-900/30'\n : 'bg-blue-100 dark:bg-blue-900/30'\n )}\n >\n {isPast ? (\n <AlertTriangle className=\"h-4 w-4 text-red-600 dark:text-red-400\" />\n ) : isUrgent ? (\n <Clock className=\"h-4 w-4 text-amber-600 dark:text-amber-400\" />\n ) : (\n <Wrench className=\"h-4 w-4 text-blue-600 dark:text-blue-400\" />\n )}\n </div>\n <div>\n <p className=\"font-medium text-text-primary\">{contract.propertyTitle}</p>\n <p className=\"text-sm text-text-secondary\">\n {contract.packageName} &middot; {contract.providerName}\n </p>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {contract.servicesIncluded.slice(0, 3).map((service, idx) => (\n <span\n key={idx}\n className=\"inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {service}\n </span>\n ))}\n {contract.servicesIncluded.length > 3 && (\n <span className=\"inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n +{contract.servicesIncluded.length - 3} more\n </span>\n )}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"text-right\">\n <p className=\"text-sm font-medium text-text-primary\">{formatDate(contract.nextServiceDate)}</p>\n <p\n className={cn(\n 'text-xs',\n isPast\n ? 'text-red-600 dark:text-red-400'\n : isUrgent\n ? 'text-amber-600 dark:text-amber-400'\n : 'text-text-secondary'\n )}\n >\n {isPast\n ? `${Math.abs(daysUntil)} days overdue`\n : daysUntil === 0\n ? 'Today'\n : `In ${daysUntil} days`}\n </p>\n </div>\n <StatusBadge\n label={contract.status.replace('_', ' ')}\n variant={getStatusVariant(contract.status)}\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n\n {/* Contracts Table */}\n <div>\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">All Contracts</h2>\n <FilterBar\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder=\"Search contracts, providers, properties...\"\n />\n <div className=\"mt-4\">\n {filtered.length > 0 ? (\n <DataTable columns={contractColumns} data={filtered} keyField=\"id\" pageSize={10} />\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Shield className=\"h-12 w-12\" />}\n title=\"No contracts found\"\n description=\"Try adjusting your search criteria or create a new contract.\"\n action={\n <button className=\"inline-flex items-center gap-2 rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90\">\n <Plus className=\"h-4 w-4\" />\n New Contract\n </button>\n }\n />\n )}\n </div>\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AMCManagementPage.js","names":[],"sources":["../../../../src/housingvista/pages/amc/AMCManagementPage.tsx"],"sourcesContent":["import { useState, useMemo, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { Shield, DollarSign, Calendar, Plus, Download, Clock, AlertTriangle, Wrench, RotateCcw } from 'lucide-react';\nimport {\n Button,\n EmphasisPanel,\n NextSteps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout } from '../../components';\nimport { StatCard } from '../../components';\nimport { DataTable, type Column } from '../../components';\nimport { StatusBadge } from '../../components';\nimport { FilterBar } from '../../components';\nimport { EmptyState } from '../../components';\nimport { useAMCContracts, useCreateAmcContract } from '../../hooks';\nimport { cn, formatCurrency, formatDate } from '../../utils/helpers';\nimport { notify } from '../../lib/toast';\nimport type { AMCContract } 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\ntype AmcStatus = 'active' | 'expiring_soon' | 'expired' | 'cancelled';\n\nfunction toIso(value: string): string {\n return value ? new Date(value).toISOString() : '';\n}\n\nfunction getStatusVariant(status: AMCContract['status']): 'success' | 'warning' | 'error' | 'muted' {\n switch (status) {\n case 'active':\n return 'success';\n case 'expiring_soon':\n return 'warning';\n case 'expired':\n return 'error';\n case 'cancelled':\n return 'muted';\n default:\n return 'muted';\n }\n}\n\nexport function AMCManagementPage() {\n const navigate = useNavigate();\n const { data: amcContracts } = useAMCContracts();\n const [search, setSearch] = useState('');\n\n const { createAmcContract, loading: creating } = useCreateAmcContract();\n\n const [createOpen, setCreateOpen] = useState(false);\n const [propertyTitle, setPropertyTitle] = useState('');\n const [packageName, setPackageName] = useState('');\n const [providerName, setProviderName] = useState('');\n const [monthlyCost, setMonthlyCost] = useState('');\n const [startDate, setStartDate] = useState('');\n const [endDate, setEndDate] = useState('');\n const [status, setStatus] = useState<AmcStatus>('active');\n const [servicesIncluded, setServicesIncluded] = useState('');\n\n const resetForm = () => {\n setPropertyTitle('');\n setPackageName('');\n setProviderName('');\n setMonthlyCost('');\n setStartDate('');\n setEndDate('');\n setStatus('active');\n setServicesIncluded('');\n };\n\n const openCreate = () => {\n resetForm();\n setCreateOpen(true);\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n const cost = Number(monthlyCost);\n if (!propertyTitle.trim() || !packageName.trim() || !providerName.trim()) {\n notify.warning('Missing details', 'Property, package and provider are required.');\n return;\n }\n if (!Number.isFinite(cost) || cost <= 0) {\n notify.warning('Enter a valid monthly cost');\n return;\n }\n const services = servicesIncluded\n .split(',')\n .map((s) => s.trim())\n .filter((s) => s.length > 0);\n try {\n await createAmcContract({\n propertyTitle: propertyTitle.trim(),\n packageName: packageName.trim(),\n providerName: providerName.trim(),\n monthlyCost: cost,\n startDate: toIso(startDate),\n endDate: toIso(endDate),\n status,\n servicesIncluded: services.length > 0 ? services : undefined,\n });\n notify.success('Contract created', `${packageName.trim()} added for ${propertyTitle.trim()}.`);\n setCreateOpen(false);\n resetForm();\n } catch (err) {\n notify.error('Could not create contract', (err as Error).message);\n }\n };\n\n const filtered = useMemo(() => {\n if (!search) return amcContracts;\n const q = search.toLowerCase();\n return amcContracts.filter(\n (c) =>\n c.propertyTitle.toLowerCase().includes(q) ||\n c.providerName.toLowerCase().includes(q) ||\n c.packageName.toLowerCase().includes(q)\n );\n }, [amcContracts, search]);\n\n const stats = useMemo(() => {\n const activeContracts = amcContracts.filter((c) => c.status === 'active' || c.status === 'expiring_soon').length;\n const pendingRenewals = amcContracts.filter((c) => c.status === 'expiring_soon').length;\n const totalMonthlySpent = amcContracts\n .filter((c) => c.status === 'active' || c.status === 'expiring_soon')\n .reduce((sum, c) => sum + c.monthlyCost, 0);\n const upcomingServices = amcContracts.filter((c) => {\n if (!c.nextServiceDate) return false;\n const serviceDate = new Date(c.nextServiceDate);\n const now = new Date();\n const daysUntil = (serviceDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24);\n return daysUntil >= 0 && daysUntil <= 30;\n }).length;\n return { activeContracts, pendingRenewals, totalMonthlySpent, upcomingServices };\n }, [amcContracts]);\n\n const scheduledServices = useMemo(\n () =>\n amcContracts\n .filter((c) => c.nextServiceDate && (c.status === 'active' || c.status === 'expiring_soon'))\n .sort((a, b) => new Date(a.nextServiceDate).getTime() - new Date(b.nextServiceDate).getTime()),\n [amcContracts]\n );\n\n const contractColumns: Column<AMCContract>[] = [\n {\n key: 'packageName',\n header: 'Contract',\n render: (item) => (\n <div>\n <div className=\"font-medium text-text-primary\">{item.packageName}</div>\n <div className=\"text-xs text-text-secondary\">{item.propertyTitle}</div>\n </div>\n ),\n },\n {\n key: 'providerName',\n header: 'Provider',\n render: (item) => <span className=\"text-sm text-text-primary\">{item.providerName}</span>,\n },\n {\n key: 'servicesIncluded',\n header: 'Coverage',\n render: (item) => (\n <div className=\"max-w-[200px]\">\n <span className=\"text-sm text-text-primary\">{item.servicesIncluded.length} services</span>\n <p className=\"truncate text-xs text-text-secondary\">\n {item.servicesIncluded.slice(0, 2).join(', ')}\n {item.servicesIncluded.length > 2 && ` +${item.servicesIncluded.length - 2} more`}\n </p>\n </div>\n ),\n },\n {\n key: 'monthlyCost',\n header: 'Cost',\n render: (item) => (\n <div>\n <span className=\"font-medium text-text-primary\">{formatCurrency(item.monthlyCost)}</span>\n <span className=\"text-xs text-text-secondary\">/mo</span>\n </div>\n ),\n },\n {\n key: 'startDate',\n header: 'Start',\n render: (item) => <span className=\"text-sm text-text-primary\">{formatDate(item.startDate)}</span>,\n },\n {\n key: 'endDate',\n header: 'End',\n render: (item) => <span className=\"text-sm text-text-primary\">{formatDate(item.endDate)}</span>,\n },\n {\n key: 'status',\n header: 'Status',\n render: (item) => (\n <StatusBadge label={item.status.replace('_', ' ')} variant={getStatusVariant(item.status)} dot />\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"AMC Management\"\n description=\"Manage Annual Maintenance Contracts and service packages\"\n purpose=\"Keep your properties maintained without surprises. Track every Annual Maintenance Contract, see what each covers and costs, get ahead of renewals, and know which services are due in the next 30 days so nothing slips.\"\n actions={\n <div className=\"flex items-center gap-2\">\n <button className=\"inline-flex items-center gap-2 rounded-md border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary transition-colors hover:bg-bg-sunken\">\n <Download className=\"h-4 w-4\" />\n Export\n </button>\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n New Contract\n </Button>\n </div>\n }\n >\n {/* 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 label=\"Active Contracts\" value={stats.activeContracts} icon={<Shield className=\"h-4 w-4\" />} />\n <StatCard\n label=\"Pending Renewals\"\n value={stats.pendingRenewals}\n icon={<RotateCcw className=\"h-4 w-4\" />}\n trend={stats.pendingRenewals > 0 ? 'up' : 'stable'}\n change={stats.pendingRenewals > 0 ? stats.pendingRenewals : 0}\n />\n <StatCard\n label=\"Total Monthly Spent\"\n value={stats.totalMonthlySpent}\n prefix=\"$\"\n icon={<DollarSign className=\"h-4 w-4\" />}\n />\n <StatCard label=\"Upcoming Services\" value={stats.upcomingServices} icon={<Calendar className=\"h-4 w-4\" />} />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-amc\"\n steps={[\n {\n id: 'pick-property',\n label: 'Add coverage for a property',\n description: 'Choose a property to set up a new maintenance contract.',\n onClick: () => navigate('/properties'),\n },\n {\n id: 'compare-providers',\n label: 'Compare your providers',\n description: 'Search by provider name to weigh coverage and monthly cost.',\n onClick: () => {\n const firstProvider = amcContracts[0]?.providerName;\n if (firstProvider) setSearch(firstProvider);\n },\n },\n {\n id: 'check-legal',\n label: 'Review contract paperwork',\n description: 'Open the legal hub to manage the underlying documents.',\n onClick: () => navigate('/legal'),\n },\n ]}\n />\n\n {/* Service Schedule Section */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm\">\n <h3 className=\"mb-4 text-lg font-semibold text-text-primary\">Upcoming Service Schedule</h3>\n {scheduledServices.length === 0 ? (\n <EmptyState\n illustration=\"empty-generic\"\n title=\"No services scheduled\"\n description=\"Once your active contracts have upcoming service dates, they'll be listed here in order of priority.\"\n className=\"border-0 bg-transparent p-6\"\n />\n ) : (\n <div className=\"space-y-3\">\n {scheduledServices.map((contract) => {\n const serviceDate = new Date(contract.nextServiceDate);\n const now = new Date();\n const daysUntil = Math.ceil((serviceDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));\n const isUrgent = daysUntil <= 7;\n const isPast = daysUntil < 0;\n\n return (\n <div\n key={contract.id}\n className=\"flex flex-col gap-3 rounded-lg bg-bg-sunken/50 p-4 sm:flex-row sm:items-center sm:justify-between\"\n >\n <div className=\"flex items-start gap-3\">\n <div\n className={cn(\n 'rounded-lg p-2',\n isPast\n ? 'bg-status-error-bg-subtle'\n : isUrgent\n ? 'bg-status-warning-bg-subtle'\n : 'bg-status-info-bg-subtle'\n )}\n >\n {isPast ? (\n <AlertTriangle className=\"h-4 w-4 text-status-error-text\" />\n ) : isUrgent ? (\n <Clock className=\"h-4 w-4 text-status-warning-text\" />\n ) : (\n <Wrench className=\"h-4 w-4 text-status-info-text\" />\n )}\n </div>\n <div>\n <p className=\"font-medium text-text-primary\">{contract.propertyTitle}</p>\n <p className=\"text-sm text-text-secondary\">\n {contract.packageName} &middot; {contract.providerName}\n </p>\n <div className=\"mt-1 flex flex-wrap gap-1\">\n {contract.servicesIncluded.slice(0, 3).map((service, idx) => (\n <span\n key={idx}\n className=\"inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {service}\n </span>\n ))}\n {contract.servicesIncluded.length > 3 && (\n <span className=\"inline-block rounded-md bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\">\n +{contract.servicesIncluded.length - 3} more\n </span>\n )}\n </div>\n </div>\n </div>\n <div className=\"flex items-center gap-3\">\n <div className=\"text-right\">\n <p className=\"text-sm font-medium text-text-primary\">{formatDate(contract.nextServiceDate)}</p>\n <p\n className={cn(\n 'text-xs',\n isPast\n ? 'text-status-error-text'\n : isUrgent\n ? 'text-status-warning-text'\n : 'text-text-secondary'\n )}\n >\n {isPast\n ? `${Math.abs(daysUntil)} days overdue`\n : daysUntil === 0\n ? 'Today'\n : `In ${daysUntil} days`}\n </p>\n </div>\n <StatusBadge\n label={contract.status.replace('_', ' ')}\n variant={getStatusVariant(contract.status)}\n />\n </div>\n </div>\n );\n })}\n </div>\n )}\n </div>\n\n {/* Contracts Table */}\n <div>\n <h2 className=\"mb-4 text-lg font-semibold text-text-primary\">All Contracts</h2>\n <FilterBar\n searchValue={search}\n onSearchChange={setSearch}\n searchPlaceholder=\"Search contracts, providers, properties...\"\n />\n <div className=\"mt-4\">\n {filtered.length > 0 ? (\n <DataTable columns={contractColumns} data={filtered} keyField=\"id\" pageSize={10} />\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Shield className=\"h-12 w-12\" />}\n title=\"No contracts found\"\n description=\"Try adjusting your search criteria or create a new contract.\"\n action={\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n New Contract\n </Button>\n }\n />\n )}\n </div>\n </div>\n\n {/* New Contract dialog */}\n <ResponsiveDialog open={createOpen} onOpenChange={setCreateOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <form onSubmit={handleCreate}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>New maintenance contract</ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n Set up an Annual Maintenance Contract to track coverage, cost and renewal dates.\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\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\">Property *</label>\n <input\n type=\"text\"\n required\n placeholder=\"e.g. Maple Court\"\n value={propertyTitle}\n onChange={(e) => setPropertyTitle(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\">Package *</label>\n <input\n type=\"text\"\n required\n placeholder=\"e.g. Premium Care\"\n value={packageName}\n onChange={(e) => setPackageName(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\">Provider *</label>\n <input\n type=\"text\"\n required\n placeholder=\"Service company\"\n value={providerName}\n onChange={(e) => setProviderName(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\">Monthly cost *</label>\n <input\n type=\"number\"\n required\n min={0}\n step=\"0.01\"\n placeholder=\"0.00\"\n value={monthlyCost}\n onChange={(e) => setMonthlyCost(e.target.value)}\n className={inputClass}\n />\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-3\">\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\">End date</label>\n <input\n type=\"date\"\n value={endDate}\n onChange={(e) => setEndDate(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\">Status</label>\n <select\n value={status}\n onChange={(e) => setStatus(e.target.value as AmcStatus)}\n className={inputClass}\n >\n <option value=\"active\">Active</option>\n <option value=\"expiring_soon\">Expiring soon</option>\n <option value=\"expired\">Expired</option>\n <option value=\"cancelled\">Cancelled</option>\n </select>\n </div>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">Services included</label>\n <input\n type=\"text\"\n placeholder=\"Comma-separated, e.g. Plumbing, Electrical, HVAC\"\n value={servicesIncluded}\n onChange={(e) => setServicesIncluded(e.target.value)}\n className={inputClass}\n />\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}>\n {creating ? 'Saving…' : 'Create contract'}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n}\n"],"mappings":"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"}