@burdenoff/microfe-housingvista 2026.703.11 → 2026.703.13

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.js +31 -20
  2. package/dist/housingvista/HousingVistaRoutes.js.map +1 -1
  3. package/dist/housingvista/components/ContactOwnerDialog.js +74 -58
  4. package/dist/housingvista/components/ContactOwnerDialog.js.map +1 -1
  5. package/dist/housingvista/components/PropertyCard.js +92 -67
  6. package/dist/housingvista/components/PropertyCard.js.map +1 -1
  7. package/dist/housingvista/hooks/messages.js +66 -0
  8. package/dist/housingvista/hooks/messages.js.map +1 -0
  9. package/dist/housingvista/pages/HomePage.js +182 -146
  10. package/dist/housingvista/pages/HomePage.js.map +1 -1
  11. package/dist/housingvista/pages/amc/AMCManagementPage.js +212 -217
  12. package/dist/housingvista/pages/amc/AMCManagementPage.js.map +1 -1
  13. package/dist/housingvista/pages/analytics/AnalyticsPage.js +377 -213
  14. package/dist/housingvista/pages/analytics/AnalyticsPage.js.map +1 -1
  15. package/dist/housingvista/pages/assets/AssetDetailPage.js +237 -144
  16. package/dist/housingvista/pages/assets/AssetDetailPage.js.map +1 -1
  17. package/dist/housingvista/pages/assets/AssetManagementPage.js +357 -233
  18. package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
  19. package/dist/housingvista/pages/chat/ChatPage.js +260 -0
  20. package/dist/housingvista/pages/chat/ChatPage.js.map +1 -0
  21. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js +157 -154
  22. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js.map +1 -1
  23. package/dist/housingvista/pages/finance/HomeLoansPage.js +162 -161
  24. package/dist/housingvista/pages/finance/HomeLoansPage.js.map +1 -1
  25. package/dist/housingvista/pages/investments/InvestmentDetailPage.js +3 -3
  26. package/dist/housingvista/pages/investments/InvestmentDetailPage.js.map +1 -1
  27. package/dist/housingvista/pages/investments/InvestmentsPage.js +347 -234
  28. package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
  29. package/dist/housingvista/pages/legal/LegalPage.js +146 -119
  30. package/dist/housingvista/pages/legal/LegalPage.js.map +1 -1
  31. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js +132 -132
  32. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js.map +1 -1
  33. package/dist/housingvista/pages/market/AreaInsightsPage.js +150 -115
  34. package/dist/housingvista/pages/market/AreaInsightsPage.js.map +1 -1
  35. package/dist/housingvista/pages/market/MarketAnalyticsPage.js +321 -203
  36. package/dist/housingvista/pages/market/MarketAnalyticsPage.js.map +1 -1
  37. package/dist/housingvista/pages/marketplace/MarketplacePage.js +89 -77
  38. package/dist/housingvista/pages/marketplace/MarketplacePage.js.map +1 -1
  39. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js +2 -2
  40. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js.map +1 -1
  41. package/dist/housingvista/pages/offers/OffersPage.js +297 -172
  42. package/dist/housingvista/pages/offers/OffersPage.js.map +1 -1
  43. package/dist/housingvista/pages/properties/AddPropertyPage.js +37 -13
  44. package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
  45. package/dist/housingvista/pages/properties/PropertiesPage.js +1 -0
  46. package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
  47. package/dist/housingvista/pages/properties/PropertyDetailPage.js +803 -583
  48. package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
  49. package/dist/housingvista/pages/rental/RentalManagementPage.js +513 -418
  50. package/dist/housingvista/pages/rental/RentalManagementPage.js.map +1 -1
  51. package/dist/housingvista/pages/shortlist/ShortlistPage.js +43 -30
  52. package/dist/housingvista/pages/shortlist/ShortlistPage.js.map +1 -1
  53. package/dist/housingvista/pages/transactions/TransactionDetailPage.js +207 -199
  54. package/dist/housingvista/pages/transactions/TransactionDetailPage.js.map +1 -1
  55. package/dist/housingvista/pages/transactions/TransactionsPage.js +204 -84
  56. package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
  57. package/dist/housingvista/pages/transactions/milestones.js +68 -0
  58. package/dist/housingvista/pages/transactions/milestones.js.map +1 -0
  59. package/dist/housingvista/pages/verification/VerificationPage.js +175 -125
  60. package/dist/housingvista/pages/verification/VerificationPage.js.map +1 -1
  61. package/dist/housingvista/pages/viewings/ViewingsPage.js +241 -136
  62. package/dist/housingvista/pages/viewings/ViewingsPage.js.map +1 -1
  63. package/dist/housingvista/utils/helpers.js +26 -7
  64. package/dist/housingvista/utils/helpers.js.map +1 -1
  65. package/dist/node_modules/lodash/maxBy.js +17 -0
  66. package/dist/node_modules/lodash/maxBy.js.map +1 -0
  67. package/dist/node_modules/lodash/minBy.js +17 -0
  68. package/dist/node_modules/lodash/minBy.js.map +1 -0
  69. package/dist/node_modules/recharts/es6/chart/BarChart.js +24 -0
  70. package/dist/node_modules/recharts/es6/chart/BarChart.js.map +1 -0
  71. package/dist/node_modules/recharts/es6/chart/PieChart.js +34 -0
  72. package/dist/node_modules/recharts/es6/chart/PieChart.js.map +1 -0
  73. package/dist/node_modules/recharts/es6/polar/Pie.js +435 -0
  74. package/dist/node_modules/recharts/es6/polar/Pie.js.map +1 -0
  75. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js +215 -0
  76. package/dist/node_modules/recharts/es6/polar/PolarAngleAxis.js.map +1 -0
  77. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js +268 -0
  78. package/dist/node_modules/recharts/es6/polar/PolarRadiusAxis.js.map +1 -0
  79. package/dist/node_modules/recharts/es6/shape/Polygon.js +112 -0
  80. package/dist/node_modules/recharts/es6/shape/Polygon.js.map +1 -0
  81. package/dist/node_modules/recharts/es6/util/PolarUtils.js +133 -51
  82. package/dist/node_modules/recharts/es6/util/PolarUtils.js.map +1 -1
  83. package/package.json +1 -1
@@ -1,12 +1,17 @@
1
- import { cn as e, formatCurrency as t, formatNumber as n } from "../utils/helpers.js";
1
+ import { cn as e, formatCompactCurrency as t, formatNumber as n } from "../utils/helpers.js";
2
2
  import { StatusBadge as r } from "./StatusBadge.js";
3
- import { Bath as i, Bed as a, Heart as o, MapPin as s, Square as c } from "lucide-react";
4
- import { jsx as l, jsxs as u } from "react/jsx-runtime";
3
+ import { useState as i } from "react";
4
+ import { Bath as a, Bed as o, Heart as s, Home as c, MapPin as l, Square as u } from "lucide-react";
5
+ import { jsx as d, jsxs as f } from "react/jsx-runtime";
5
6
  //#region src/housingvista/components/PropertyCard.tsx
6
- var d = {
7
+ var p = {
7
8
  available: "success",
8
9
  active: "success",
9
10
  listed: "success",
11
+ for_sale: "success",
12
+ "for sale": "success",
13
+ for_rent: "info",
14
+ "for rent": "info",
10
15
  pending: "warning",
11
16
  "under contract": "warning",
12
17
  "under offer": "warning",
@@ -15,92 +20,112 @@ var d = {
15
20
  off_market: "muted",
16
21
  "off market": "muted",
17
22
  draft: "muted"
18
- }, f = ({ title: f, price: p, priceType: m, pricePeriod: h, location: g, bedrooms: _, bathrooms: v, area: y, imageUrl: b, status: x, type: S, onClick: C, className: w, isShortlisted: T, onToggleShortlist: E }) => {
19
- let D = m === "rent" ? `${t(p)}${h ? `/${h}` : "/mo"}` : t(p), O = d[x.toLowerCase()] ?? "default";
20
- return /* @__PURE__ */ u("div", {
21
- className: e("group overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2", C && "cursor-pointer", w),
22
- onClick: C,
23
- children: [/* @__PURE__ */ u("div", {
24
- className: "relative aspect-[16/10] overflow-hidden",
23
+ }, m = () => /* @__PURE__ */ f("div", {
24
+ className: "relative flex h-full w-full items-center justify-center overflow-hidden bg-gradient-to-br from-[var(--color-action-primary-bg)]/15 via-bg-sunken to-[var(--color-accent-blue)]/15",
25
+ children: [/* @__PURE__ */ d("div", {
26
+ className: "absolute inset-0 opacity-[0.35]",
27
+ style: {
28
+ backgroundImage: "radial-gradient(circle at 1px 1px, var(--color-border-seam, rgba(120,120,120,.25)) 1px, transparent 0)",
29
+ backgroundSize: "16px 16px"
30
+ }
31
+ }), /* @__PURE__ */ f("div", {
32
+ className: "relative flex flex-col items-center gap-2 text-text-secondary/70",
33
+ children: [/* @__PURE__ */ d(c, { className: "h-9 w-9" }), /* @__PURE__ */ d("span", {
34
+ className: "text-[11px] font-medium tracking-wide",
35
+ children: "HousingVista"
36
+ })]
37
+ })]
38
+ }), h = ({ title: c, price: h, priceType: g, pricePeriod: _, currency: v = "USD", location: y, bedrooms: b, bathrooms: x, area: S, imageUrl: C, status: w, type: T, onClick: E, className: D, isShortlisted: O, onToggleShortlist: k }) => {
39
+ let [A, j] = i(!1), M = !!C && !A, N = t(h, v), P = g === "rent" ? `${N}${_ ? `/${_.replace("ly", "")}` : "/mo"}` : N, F = p[w.toLowerCase()] ?? "default";
40
+ return /* @__PURE__ */ f("div", {
41
+ className: e("group flex flex-col overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2 focus-within:border-border-strong", E && "cursor-pointer", D),
42
+ onClick: E,
43
+ onKeyDown: (e) => {
44
+ E && (e.key === "Enter" || e.key === " ") && (e.preventDefault(), E());
45
+ },
46
+ role: E ? "button" : void 0,
47
+ tabIndex: E ? 0 : void 0,
48
+ "aria-label": E ? `View ${c}` : void 0,
49
+ children: [/* @__PURE__ */ f("div", {
50
+ className: "relative aspect-[16/10] shrink-0 overflow-hidden",
25
51
  children: [
26
- b ? /* @__PURE__ */ l("img", {
27
- src: b,
28
- alt: f,
29
- className: "h-full w-full object-cover"
30
- }) : /* @__PURE__ */ l("div", {
31
- className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-bg-sunken to-bg-sunken/60",
32
- children: /* @__PURE__ */ l(c, { className: "h-10 w-10 text-text-secondary/40" })
33
- }),
34
- /* @__PURE__ */ l("div", {
52
+ M ? /* @__PURE__ */ d("img", {
53
+ src: C,
54
+ alt: c,
55
+ loading: "lazy",
56
+ onError: () => j(!0),
57
+ className: "h-full w-full object-cover transition-[filter] duration-300 group-hover:brightness-[1.02]"
58
+ }) : /* @__PURE__ */ d(m, {}),
59
+ /* @__PURE__ */ d("div", { className: "pointer-events-none absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-bg-overlay/75 to-transparent" }),
60
+ /* @__PURE__ */ d("div", {
35
61
  className: "absolute left-3 top-3",
36
- children: /* @__PURE__ */ l(r, {
37
- label: x,
38
- variant: O,
62
+ children: /* @__PURE__ */ d(r, {
63
+ label: w,
64
+ variant: F,
39
65
  dot: !0
40
66
  })
41
67
  }),
42
- E && /* @__PURE__ */ l("button", {
68
+ k && /* @__PURE__ */ d("button", {
69
+ type: "button",
43
70
  onClick: (e) => {
44
- e.stopPropagation(), E();
71
+ e.stopPropagation(), k();
45
72
  },
46
- className: e("absolute right-3 top-3 rounded-full bg-bg-surface/80 p-1.5 backdrop-blur-sm transition-colors hover:bg-bg-surface", T ? "text-status-error-text" : "text-text-secondary"),
47
- "aria-label": T ? "Remove from shortlist" : "Save to shortlist",
48
- children: /* @__PURE__ */ l(o, { className: e("h-4 w-4", T && "fill-current") })
73
+ className: e("absolute right-3 top-3 rounded-full bg-bg-surface/85 p-2 shadow-elevation-1 backdrop-blur-sm transition-colors hover:bg-bg-surface focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]", O ? "text-status-error-text" : "text-text-secondary"),
74
+ "aria-pressed": O,
75
+ "aria-label": O ? "Remove from shortlist" : "Save to shortlist",
76
+ children: /* @__PURE__ */ d(s, { className: e("h-4 w-4", O && "fill-current") })
49
77
  }),
50
- /* @__PURE__ */ l("div", {
78
+ /* @__PURE__ */ d("div", {
51
79
  className: "absolute bottom-3 left-3",
52
- children: /* @__PURE__ */ l("span", {
53
- className: "rounded-md bg-bg-surface/80 px-2 py-1 text-xs font-medium text-text-primary backdrop-blur-sm",
54
- children: S
80
+ children: /* @__PURE__ */ d("span", {
81
+ className: "text-lg font-bold text-text-inverse drop-shadow-sm",
82
+ children: P
83
+ })
84
+ }),
85
+ /* @__PURE__ */ d("div", {
86
+ className: "absolute bottom-3 right-3",
87
+ children: /* @__PURE__ */ d("span", {
88
+ className: "rounded-md bg-bg-surface/85 px-2 py-1 text-xs font-medium capitalize text-text-primary backdrop-blur-sm",
89
+ children: T
55
90
  })
56
91
  })
57
92
  ]
58
- }), /* @__PURE__ */ u("div", {
59
- className: "p-4",
93
+ }), /* @__PURE__ */ f("div", {
94
+ className: "flex flex-1 flex-col p-4",
60
95
  children: [
61
- /* @__PURE__ */ u("div", {
62
- className: "flex items-baseline justify-between gap-2",
63
- children: [/* @__PURE__ */ l("span", {
64
- className: "text-lg font-bold text-text-primary",
65
- children: D
66
- }), m === "sale" && /* @__PURE__ */ l("span", {
67
- className: "text-xs font-medium text-text-secondary",
68
- children: "For Sale"
69
- })]
70
- }),
71
- /* @__PURE__ */ l("h3", {
72
- className: "mt-1 truncate text-sm font-medium text-text-primary",
73
- children: f
96
+ /* @__PURE__ */ d("h3", {
97
+ className: "truncate text-sm font-semibold text-text-primary",
98
+ children: c
74
99
  }),
75
- /* @__PURE__ */ u("div", {
76
- className: "mt-1.5 flex items-center gap-1 text-text-secondary",
77
- children: [/* @__PURE__ */ l(s, { className: "h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ l("span", {
100
+ /* @__PURE__ */ f("div", {
101
+ className: "mt-1 flex items-center gap-1 text-text-secondary",
102
+ children: [/* @__PURE__ */ d(l, { className: "h-3.5 w-3.5 shrink-0" }), /* @__PURE__ */ d("span", {
78
103
  className: "truncate text-xs",
79
- children: g
104
+ children: y
80
105
  })]
81
106
  }),
82
- /* @__PURE__ */ u("div", {
83
- className: "mt-3 flex items-center gap-3 border-t border-border-subtle pt-3",
107
+ /* @__PURE__ */ f("div", {
108
+ className: "mt-3 flex items-center gap-4 border-t border-border-subtle pt-3",
84
109
  children: [
85
- _ != null && /* @__PURE__ */ u("div", {
86
- className: "flex items-center gap-1 text-xs text-text-secondary",
87
- children: [/* @__PURE__ */ l(a, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ u("span", { children: [
88
- _,
110
+ b != null && /* @__PURE__ */ f("div", {
111
+ className: "flex items-center gap-1.5 text-xs text-text-secondary",
112
+ children: [/* @__PURE__ */ d(o, { className: "h-4 w-4" }), /* @__PURE__ */ f("span", { children: [
113
+ b,
89
114
  " ",
90
- _ === 1 ? "Bed" : "Beds"
115
+ b === 1 ? "Bed" : "Beds"
91
116
  ] })]
92
117
  }),
93
- v != null && /* @__PURE__ */ u("div", {
94
- className: "flex items-center gap-1 text-xs text-text-secondary",
95
- children: [/* @__PURE__ */ l(i, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ u("span", { children: [
96
- v,
118
+ x != null && /* @__PURE__ */ f("div", {
119
+ className: "flex items-center gap-1.5 text-xs text-text-secondary",
120
+ children: [/* @__PURE__ */ d(a, { className: "h-4 w-4" }), /* @__PURE__ */ f("span", { children: [
121
+ x,
97
122
  " ",
98
- v === 1 ? "Bath" : "Baths"
123
+ x === 1 ? "Bath" : "Baths"
99
124
  ] })]
100
125
  }),
101
- /* @__PURE__ */ u("div", {
102
- className: "flex items-center gap-1 text-xs text-text-secondary",
103
- children: [/* @__PURE__ */ l(c, { className: "h-3.5 w-3.5" }), /* @__PURE__ */ u("span", { children: [n(y), " sq ft"] })]
126
+ /* @__PURE__ */ f("div", {
127
+ className: "flex items-center gap-1.5 text-xs text-text-secondary",
128
+ children: [/* @__PURE__ */ d(u, { className: "h-4 w-4" }), /* @__PURE__ */ f("span", { children: [n(S), " sq ft"] })]
104
129
  })
105
130
  ]
106
131
  })
@@ -109,6 +134,6 @@ var d = {
109
134
  });
110
135
  };
111
136
  //#endregion
112
- export { f as PropertyCard };
137
+ export { h as PropertyCard };
113
138
 
114
139
  //# sourceMappingURL=PropertyCard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"PropertyCard.js","names":[],"sources":["../../../src/housingvista/components/PropertyCard.tsx"],"sourcesContent":["import { type FC } from 'react';\nimport { MapPin, Bed, Bath, Square, Heart } from 'lucide-react';\nimport { cn, formatCurrency, formatNumber } from '../utils/helpers';\nimport { StatusBadge } from './StatusBadge';\n\ninterface PropertyCardProps {\n id: string;\n title: string;\n price: number;\n priceType: 'sale' | 'rent';\n pricePeriod?: string;\n location: string;\n bedrooms?: number;\n bathrooms?: number;\n area: number;\n imageUrl?: string;\n status: string;\n type: string;\n onClick?: () => void;\n className?: string;\n /** When provided the heart becomes a controlled shortlist toggle. */\n isShortlisted?: boolean;\n onToggleShortlist?: () => void;\n}\n\nconst statusVariantMap: Record<string, 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted'> = {\n available: 'success',\n active: 'success',\n listed: 'success',\n pending: 'warning',\n 'under contract': 'warning',\n 'under offer': 'warning',\n sold: 'error',\n rented: 'error',\n off_market: 'muted',\n 'off market': 'muted',\n draft: 'muted',\n};\n\nexport const PropertyCard: FC<PropertyCardProps> = ({\n title,\n price,\n priceType,\n pricePeriod,\n location,\n bedrooms,\n bathrooms,\n area,\n imageUrl,\n status,\n type,\n onClick,\n className,\n isShortlisted,\n onToggleShortlist,\n}) => {\n const priceDisplay =\n priceType === 'rent' ? `${formatCurrency(price)}${pricePeriod ? `/${pricePeriod}` : '/mo'}` : formatCurrency(price);\n\n const badgeVariant = statusVariantMap[status.toLowerCase()] ?? 'default';\n\n return (\n <div\n className={cn(\n 'group overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2',\n onClick && 'cursor-pointer',\n className\n )}\n onClick={onClick}\n >\n {/* Image Section */}\n <div className=\"relative aspect-[16/10] overflow-hidden\">\n {imageUrl ? (\n <img src={imageUrl} alt={title} className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-bg-sunken to-bg-sunken/60\">\n <Square className=\"h-10 w-10 text-text-secondary/40\" />\n </div>\n )}\n\n {/* Overlays */}\n <div className=\"absolute left-3 top-3\">\n <StatusBadge label={status} variant={badgeVariant} dot />\n </div>\n {onToggleShortlist && (\n <button\n onClick={(e) => {\n e.stopPropagation();\n onToggleShortlist();\n }}\n className={cn(\n 'absolute right-3 top-3 rounded-full bg-bg-surface/80 p-1.5 backdrop-blur-sm transition-colors hover:bg-bg-surface',\n isShortlisted ? 'text-status-error-text' : 'text-text-secondary'\n )}\n aria-label={isShortlisted ? 'Remove from shortlist' : 'Save to shortlist'}\n >\n <Heart className={cn('h-4 w-4', isShortlisted && 'fill-current')} />\n </button>\n )}\n <div className=\"absolute bottom-3 left-3\">\n <span className=\"rounded-md bg-bg-surface/80 px-2 py-1 text-xs font-medium text-text-primary backdrop-blur-sm\">\n {type}\n </span>\n </div>\n </div>\n\n {/* Content Section */}\n <div className=\"p-4\">\n {/* Price */}\n <div className=\"flex items-baseline justify-between gap-2\">\n <span className=\"text-lg font-bold text-text-primary\">{priceDisplay}</span>\n {priceType === 'sale' && <span className=\"text-xs font-medium text-text-secondary\">For Sale</span>}\n </div>\n\n {/* Title */}\n <h3 className=\"mt-1 truncate text-sm font-medium text-text-primary\">{title}</h3>\n\n {/* Location */}\n <div className=\"mt-1.5 flex items-center gap-1 text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate text-xs\">{location}</span>\n </div>\n\n {/* Specs Row */}\n <div className=\"mt-3 flex items-center gap-3 border-t border-border-subtle pt-3\">\n {bedrooms != null && (\n <div className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Bed className=\"h-3.5 w-3.5\" />\n <span>\n {bedrooms} {bedrooms === 1 ? 'Bed' : 'Beds'}\n </span>\n </div>\n )}\n {bathrooms != null && (\n <div className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Bath className=\"h-3.5 w-3.5\" />\n <span>\n {bathrooms} {bathrooms === 1 ? 'Bath' : 'Baths'}\n </span>\n </div>\n )}\n <div className=\"flex items-center gap-1 text-xs text-text-secondary\">\n <Square className=\"h-3.5 w-3.5\" />\n <span>{formatNumber(area)} sq ft</span>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;AAyBA,IAAM,IAAmG;CACvG,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,kBAAkB;CAClB,eAAe;CACf,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,cAAc;CACd,OAAO;CACR,EAEY,KAAuC,EAClD,UACA,UACA,cACA,gBACA,aACA,aACA,cACA,SACA,aACA,WACA,SACA,YACA,cACA,kBACA,2BACI;CACJ,IAAM,IACJ,MAAc,SAAS,GAAG,EAAe,EAAM,GAAG,IAAc,IAAI,MAAgB,UAAU,EAAe,EAAM,EAE/G,IAAe,EAAiB,EAAO,aAAa,KAAK;AAE/D,QACE,kBAAC,OAAD;EACE,WAAW,EACT,0LACA,KAAW,kBACX,EACD;EACQ;YANX,CASE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACG,IACC,kBAAC,OAAD;KAAK,KAAK;KAAU,KAAK;KAAO,WAAU;KAA+B,CAAA,GAEzE,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD,EAAQ,WAAU,oCAAqC,CAAA;KACnD,CAAA;IAIR,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAa,OAAO;MAAQ,SAAS;MAAc,KAAA;MAAM,CAAA;KACrD,CAAA;IACL,KACC,kBAAC,UAAD;KACE,UAAU,MAAM;AAEd,MADA,EAAE,iBAAiB,EACnB,GAAmB;;KAErB,WAAW,EACT,qHACA,IAAgB,2BAA2B,sBAC5C;KACD,cAAY,IAAgB,0BAA0B;eAEtD,kBAAC,GAAD,EAAO,WAAW,EAAG,WAAW,KAAiB,eAAe,EAAI,CAAA;KAC7D,CAAA;IAEX,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,QAAD;MAAM,WAAU;gBACb;MACI,CAAA;KACH,CAAA;IACF;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,QAAD;MAAM,WAAU;gBAAuC;MAAoB,CAAA,EAC1E,MAAc,UAAU,kBAAC,QAAD;MAAM,WAAU;gBAA0C;MAAe,CAAA,CAC9F;;IAGN,kBAAC,MAAD;KAAI,WAAU;eAAuD;KAAW,CAAA;IAGhF,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wBAAyB,CAAA,EAC3C,kBAAC,QAAD;MAAM,WAAU;gBAAoB;MAAgB,CAAA,CAChD;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KAAY,QACX,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAK,WAAU,eAAgB,CAAA,EAC/B,kBAAC,QAAD,EAAA,UAAA;QACG;QAAS;QAAE,MAAa,IAAI,QAAQ;QAChC,EAAA,CAAA,CACH;;MAEP,KAAa,QACZ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,eAAgB,CAAA,EAChC,kBAAC,QAAD,EAAA,UAAA;QACG;QAAU;QAAE,MAAc,IAAI,SAAS;QACnC,EAAA,CAAA,CACH;;MAER,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,eAAgB,CAAA,EAClC,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAa,EAAK,EAAC,SAAa,EAAA,CAAA,CACnC;;MACF;;IACF;KACF"}
1
+ {"version":3,"file":"PropertyCard.js","names":[],"sources":["../../../src/housingvista/components/PropertyCard.tsx"],"sourcesContent":["import { type FC, useState } from 'react';\nimport { MapPin, Bed, Bath, Square, Heart, Home } from 'lucide-react';\nimport { cn, formatNumber, formatCompactCurrency } from '../utils/helpers';\nimport { StatusBadge } from './StatusBadge';\n\ninterface PropertyCardProps {\n id: string;\n title: string;\n price: number;\n priceType: 'sale' | 'rent';\n pricePeriod?: string;\n /** ISO currency code for the price (defaults to USD). */\n currency?: string;\n location: string;\n bedrooms?: number;\n bathrooms?: number;\n area: number;\n imageUrl?: string;\n status: string;\n type: string;\n onClick?: () => void;\n className?: string;\n /** When provided the heart becomes a controlled shortlist toggle. */\n isShortlisted?: boolean;\n onToggleShortlist?: () => void;\n}\n\nconst statusVariantMap: Record<string, 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted'> = {\n available: 'success',\n active: 'success',\n listed: 'success',\n for_sale: 'success',\n 'for sale': 'success',\n for_rent: 'info',\n 'for rent': 'info',\n pending: 'warning',\n 'under contract': 'warning',\n 'under offer': 'warning',\n sold: 'error',\n rented: 'error',\n off_market: 'muted',\n 'off market': 'muted',\n draft: 'muted',\n};\n\n/** Tasteful branded fallback shown when a listing has no files-svc image. */\nconst PropertyPlaceholder: FC = () => (\n <div className=\"relative flex h-full w-full items-center justify-center overflow-hidden bg-gradient-to-br from-[var(--color-action-primary-bg)]/15 via-bg-sunken to-[var(--color-accent-blue)]/15\">\n <div\n className=\"absolute inset-0 opacity-[0.35]\"\n style={{\n backgroundImage:\n 'radial-gradient(circle at 1px 1px, var(--color-border-seam, rgba(120,120,120,.25)) 1px, transparent 0)',\n backgroundSize: '16px 16px',\n }}\n />\n <div className=\"relative flex flex-col items-center gap-2 text-text-secondary/70\">\n <Home className=\"h-9 w-9\" />\n <span className=\"text-[11px] font-medium tracking-wide\">HousingVista</span>\n </div>\n </div>\n);\n\nexport const PropertyCard: FC<PropertyCardProps> = ({\n title,\n price,\n priceType,\n pricePeriod,\n currency = 'USD',\n location,\n bedrooms,\n bathrooms,\n area,\n imageUrl,\n status,\n type,\n onClick,\n className,\n isShortlisted,\n onToggleShortlist,\n}) => {\n const [imgFailed, setImgFailed] = useState(false);\n const showImage = Boolean(imageUrl) && !imgFailed;\n\n const compactPrice = formatCompactCurrency(price, currency);\n const priceDisplay =\n priceType === 'rent' ? `${compactPrice}${pricePeriod ? `/${pricePeriod.replace('ly', '')}` : '/mo'}` : compactPrice;\n\n const badgeVariant = statusVariantMap[status.toLowerCase()] ?? 'default';\n\n return (\n <div\n className={cn(\n 'group flex flex-col overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2 focus-within:border-border-strong',\n onClick && 'cursor-pointer',\n className\n )}\n onClick={onClick}\n onKeyDown={(e) => {\n if (onClick && (e.key === 'Enter' || e.key === ' ')) {\n e.preventDefault();\n onClick();\n }\n }}\n role={onClick ? 'button' : undefined}\n tabIndex={onClick ? 0 : undefined}\n aria-label={onClick ? `View ${title}` : undefined}\n >\n {/* Image Section */}\n <div className=\"relative aspect-[16/10] shrink-0 overflow-hidden\">\n {showImage ? (\n <img\n src={imageUrl}\n alt={title}\n loading=\"lazy\"\n onError={() => setImgFailed(true)}\n className=\"h-full w-full object-cover transition-[filter] duration-300 group-hover:brightness-[1.02]\"\n />\n ) : (\n <PropertyPlaceholder />\n )}\n\n {/* Gradient scrim so overlaid text stays legible over any photo */}\n <div className=\"pointer-events-none absolute inset-x-0 bottom-0 h-24 bg-gradient-to-t from-bg-overlay/75 to-transparent\" />\n\n {/* Status pill (top-left) */}\n <div className=\"absolute left-3 top-3\">\n <StatusBadge label={status} variant={badgeVariant} dot />\n </div>\n\n {/* Shortlist heart (top-right) */}\n {onToggleShortlist && (\n <button\n type=\"button\"\n onClick={(e) => {\n e.stopPropagation();\n onToggleShortlist();\n }}\n className={cn(\n 'absolute right-3 top-3 rounded-full bg-bg-surface/85 p-2 shadow-elevation-1 backdrop-blur-sm transition-colors hover:bg-bg-surface focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]',\n isShortlisted ? 'text-status-error-text' : 'text-text-secondary'\n )}\n aria-pressed={isShortlisted}\n aria-label={isShortlisted ? 'Remove from shortlist' : 'Save to shortlist'}\n >\n <Heart className={cn('h-4 w-4', isShortlisted && 'fill-current')} />\n </button>\n )}\n\n {/* Price overlay (bottom-left) */}\n <div className=\"absolute bottom-3 left-3\">\n <span className=\"text-lg font-bold text-text-inverse drop-shadow-sm\">{priceDisplay}</span>\n </div>\n\n {/* Category chip (bottom-right) */}\n <div className=\"absolute bottom-3 right-3\">\n <span className=\"rounded-md bg-bg-surface/85 px-2 py-1 text-xs font-medium capitalize text-text-primary backdrop-blur-sm\">\n {type}\n </span>\n </div>\n </div>\n\n {/* Content Section */}\n <div className=\"flex flex-1 flex-col p-4\">\n {/* Title */}\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{title}</h3>\n\n {/* Location */}\n <div className=\"mt-1 flex items-center gap-1 text-text-secondary\">\n <MapPin className=\"h-3.5 w-3.5 shrink-0\" />\n <span className=\"truncate text-xs\">{location}</span>\n </div>\n\n {/* Specs Row */}\n <div className=\"mt-3 flex items-center gap-4 border-t border-border-subtle pt-3\">\n {bedrooms != null && (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Bed className=\"h-4 w-4\" />\n <span>\n {bedrooms} {bedrooms === 1 ? 'Bed' : 'Beds'}\n </span>\n </div>\n )}\n {bathrooms != null && (\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Bath className=\"h-4 w-4\" />\n <span>\n {bathrooms} {bathrooms === 1 ? 'Bath' : 'Baths'}\n </span>\n </div>\n )}\n <div className=\"flex items-center gap-1.5 text-xs text-text-secondary\">\n <Square className=\"h-4 w-4\" />\n <span>{formatNumber(area)} sq ft</span>\n </div>\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":";;;;;;AA2BA,IAAM,IAAmG;CACvG,WAAW;CACX,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,YAAY;CACZ,UAAU;CACV,YAAY;CACZ,SAAS;CACT,kBAAkB;CAClB,eAAe;CACf,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,cAAc;CACd,OAAO;CACR,EAGK,UACJ,kBAAC,OAAD;CAAK,WAAU;WAAf,CACE,kBAAC,OAAD;EACE,WAAU;EACV,OAAO;GACL,iBACE;GACF,gBAAgB;GACjB;EACD,CAAA,EACF,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC5B,kBAAC,QAAD;GAAM,WAAU;aAAwC;GAAmB,CAAA,CACvE;IACF;IAGK,KAAuC,EAClD,UACA,UACA,cACA,gBACA,cAAW,OACX,aACA,aACA,cACA,SACA,aACA,WACA,SACA,YACA,cACA,kBACA,2BACI;CACJ,IAAM,CAAC,GAAW,KAAgB,EAAS,GAAM,EAC3C,IAAY,EAAQ,KAAa,CAAC,GAElC,IAAe,EAAsB,GAAO,EAAS,EACrD,IACJ,MAAc,SAAS,GAAG,IAAe,IAAc,IAAI,EAAY,QAAQ,MAAM,GAAG,KAAK,UAAU,GAEnG,IAAe,EAAiB,EAAO,aAAa,KAAK;AAE/D,QACE,kBAAC,OAAD;EACE,WAAW,EACT,0OACA,KAAW,kBACX,EACD;EACQ;EACT,YAAY,MAAM;AAChB,GAAI,MAAY,EAAE,QAAQ,WAAW,EAAE,QAAQ,SAC7C,EAAE,gBAAgB,EAClB,GAAS;;EAGb,MAAM,IAAU,WAAW,KAAA;EAC3B,UAAU,IAAU,IAAI,KAAA;EACxB,cAAY,IAAU,QAAQ,MAAU,KAAA;YAf1C,CAkBE,kBAAC,OAAD;GAAK,WAAU;aAAf;IACG,IACC,kBAAC,OAAD;KACE,KAAK;KACL,KAAK;KACL,SAAQ;KACR,eAAe,EAAa,GAAK;KACjC,WAAU;KACV,CAAA,GAEF,kBAAC,GAAD,EAAuB,CAAA;IAIzB,kBAAC,OAAD,EAAK,WAAU,2GAA4G,CAAA;IAG3H,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,GAAD;MAAa,OAAO;MAAQ,SAAS;MAAc,KAAA;MAAM,CAAA;KACrD,CAAA;IAGL,KACC,kBAAC,UAAD;KACE,MAAK;KACL,UAAU,MAAM;AAEd,MADA,EAAE,iBAAiB,EACnB,GAAmB;;KAErB,WAAW,EACT,mOACA,IAAgB,2BAA2B,sBAC5C;KACD,gBAAc;KACd,cAAY,IAAgB,0BAA0B;eAEtD,kBAAC,GAAD,EAAO,WAAW,EAAG,WAAW,KAAiB,eAAe,EAAI,CAAA;KAC7D,CAAA;IAIX,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,QAAD;MAAM,WAAU;gBAAsD;MAAoB,CAAA;KACtF,CAAA;IAGN,kBAAC,OAAD;KAAK,WAAU;eACb,kBAAC,QAAD;MAAM,WAAU;gBACb;MACI,CAAA;KACH,CAAA;IACF;MAGN,kBAAC,OAAD;GAAK,WAAU;aAAf;IAEE,kBAAC,MAAD;KAAI,WAAU;eAAoD;KAAW,CAAA;IAG7E,kBAAC,OAAD;KAAK,WAAU;eAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,wBAAyB,CAAA,EAC3C,kBAAC,QAAD;MAAM,WAAU;gBAAoB;MAAgB,CAAA,CAChD;;IAGN,kBAAC,OAAD;KAAK,WAAU;eAAf;MACG,KAAY,QACX,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAK,WAAU,WAAY,CAAA,EAC3B,kBAAC,QAAD,EAAA,UAAA;QACG;QAAS;QAAE,MAAa,IAAI,QAAQ;QAChC,EAAA,CAAA,CACH;;MAEP,KAAa,QACZ,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAM,WAAU,WAAY,CAAA,EAC5B,kBAAC,QAAD,EAAA,UAAA;QACG;QAAU;QAAE,MAAc,IAAI,SAAS;QACnC,EAAA,CAAA,CACH;;MAER,kBAAC,OAAD;OAAK,WAAU;iBAAf,CACE,kBAAC,GAAD,EAAQ,WAAU,WAAY,CAAA,EAC9B,kBAAC,QAAD,EAAA,UAAA,CAAO,EAAa,EAAK,EAAC,SAAa,EAAA,CAAA,CACnC;;MACF;;IACF;KACF"}
@@ -0,0 +1,66 @@
1
+ import { gql as e } from "@apollo/client";
2
+ import { useQuery as t } from "@apollo/client/react";
3
+ //#region src/housingvista/hooks/messages.ts
4
+ var n = e`
5
+ query HvConversations($first: Int, $sort: ConversationSort) {
6
+ conversations(first: $first, sort: $sort) {
7
+ edges {
8
+ node {
9
+ id
10
+ title
11
+ avatar
12
+ unreadCount
13
+ updatedAt
14
+ settings
15
+ lastMessage {
16
+ id
17
+ authorId
18
+ content
19
+ createdAt
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ `, r = (e) => e && typeof e == "object" && !Array.isArray(e) ? e : null, i = (e) => typeof e == "string" && e.length > 0 ? e : null, a = (e) => {
26
+ let t = r(e?.metadata), n = r(t?.sourceContext), a = r(t?.channelLink), o = r(t?.jumpToContext), s = i(n?.product), c = i(a?.channelKey);
27
+ return {
28
+ isHousingVista: s === "housingvista" || c === "housingvista-widget",
29
+ contextHref: i(o?.href) ?? i(n?.contextHref),
30
+ entityType: i(n?.entityType)
31
+ };
32
+ }, o = (e = 50) => {
33
+ let { data: r, loading: i, error: o, refetch: s } = t(n, {
34
+ variables: {
35
+ first: e,
36
+ sort: {
37
+ field: "LAST_MESSAGE_AT",
38
+ direction: "DESC"
39
+ }
40
+ },
41
+ fetchPolicy: "cache-and-network"
42
+ });
43
+ return {
44
+ data: (r?.conversations.edges ?? []).map((e) => e.node).filter((e) => a(e.settings).isHousingVista).map((e) => {
45
+ let t = a(e.settings);
46
+ return {
47
+ id: e.id,
48
+ title: e.title ?? "Conversation",
49
+ avatar: e.avatar,
50
+ unreadCount: e.unreadCount,
51
+ updatedAt: e.updatedAt,
52
+ lastMessageText: e.lastMessage?.content?.text ?? "",
53
+ lastMessageAt: e.lastMessage?.createdAt ?? null,
54
+ contextHref: t.contextHref,
55
+ entityType: t.entityType
56
+ };
57
+ }),
58
+ loading: i,
59
+ error: o,
60
+ refetch: s
61
+ };
62
+ };
63
+ //#endregion
64
+ export { o as useHousingVistaConversations };
65
+
66
+ //# sourceMappingURL=messages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"messages.js","names":[],"sources":["../../../src/housingvista/hooks/messages.ts"],"sourcesContent":["/**\n * HousingVista inbox — the conversation list behind the `/housingvista/chat`\n * (Messages) surface. Reads the current user's workspace conversations from\n * `wspace-conversations-svc` and narrows them to the threads THIS product\n * created: `resolveContextConversation` stamps every HousingVista thread with a\n * `sourceContext.product = \"housingvista\"` (and `channelLink.channelKey =\n * \"housingvista-widget\"`) inside the conversation `settings`, so we filter on\n * that. Thread reads + sends reuse the shared platform hooks\n * (`useConversationMessages` / `useSendMessage`) — no stub, no mock data.\n * @module housingvista\n */\n\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\n\nconst GET_HV_CONVERSATIONS = gql`\n query HvConversations($first: Int, $sort: ConversationSort) {\n conversations(first: $first, sort: $sort) {\n edges {\n node {\n id\n title\n avatar\n unreadCount\n updatedAt\n settings\n lastMessage {\n id\n authorId\n content\n createdAt\n }\n }\n }\n }\n }\n`;\n\n/** A HousingVista thread as shown in the inbox list. */\nexport interface HvConversationSummary {\n id: string;\n title: string;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n lastMessageText: string;\n lastMessageAt: string | null;\n /** Deep link back to the property/service the thread is about, if any. */\n contextHref: string | null;\n /** e.g. `housingvista-property`, `housingvista-marketplace-service`. */\n entityType: string | null;\n}\n\ninterface MessageContentJson {\n text?: string;\n}\n\ninterface ConversationNode {\n id: string;\n title: string | null;\n avatar: string | null;\n unreadCount: number;\n updatedAt: string;\n settings: Record<string, unknown> | null;\n lastMessage: {\n id: string;\n authorId: string;\n content: MessageContentJson | null;\n createdAt: string;\n } | null;\n}\n\ninterface HvConversationsResult {\n conversations: {\n edges: { node: ConversationNode }[];\n };\n}\n\n/** Safely read a nested object off an opaque JSON value. */\nconst asRecord = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;\n\nconst asString = (value: unknown): string | null => (typeof value === 'string' && value.length > 0 ? value : null);\n\n/**\n * A conversation belongs to HousingVista when its source context (or channel\n * link) was stamped by this product. Reads the shape written by\n * `buildContextConversationSettings` in wspace-conversations-svc.\n */\nconst readHousingVistaContext = (\n settings: Record<string, unknown> | null\n): { isHousingVista: boolean; contextHref: string | null; entityType: string | null } => {\n const metadata = asRecord(settings?.metadata);\n const sourceContext = asRecord(metadata?.sourceContext);\n const channelLink = asRecord(metadata?.channelLink);\n const jumpToContext = asRecord(metadata?.jumpToContext);\n\n const product = asString(sourceContext?.product);\n const channelKey = asString(channelLink?.channelKey);\n const isHousingVista = product === 'housingvista' || channelKey === 'housingvista-widget';\n\n return {\n isHousingVista,\n contextHref: asString(jumpToContext?.href) ?? asString(sourceContext?.contextHref),\n entityType: asString(sourceContext?.entityType),\n };\n};\n\n/**\n * The user's HousingVista conversations, most-recent first. Filtered client-side\n * to product-owned threads (see {@link readHousingVistaContext}); everything\n * else is honestly empty rather than fabricated.\n */\nexport const useHousingVistaConversations = (first = 50) => {\n const { data, loading, error, refetch } = useQuery<HvConversationsResult>(GET_HV_CONVERSATIONS, {\n variables: { first, sort: { field: 'LAST_MESSAGE_AT', direction: 'DESC' } },\n fetchPolicy: 'cache-and-network',\n });\n\n const conversations: HvConversationSummary[] = (data?.conversations.edges ?? [])\n .map((edge) => edge.node)\n .filter((node) => readHousingVistaContext(node.settings).isHousingVista)\n .map((node) => {\n const context = readHousingVistaContext(node.settings);\n return {\n id: node.id,\n title: node.title ?? 'Conversation',\n avatar: node.avatar,\n unreadCount: node.unreadCount,\n updatedAt: node.updatedAt,\n lastMessageText: node.lastMessage?.content?.text ?? '',\n lastMessageAt: node.lastMessage?.createdAt ?? null,\n contextHref: context.contextHref,\n entityType: context.entityType,\n };\n });\n\n return { data: conversations, loading, error, refetch };\n};\n"],"mappings":";;;AAeA,IAAM,IAAuB,CAAG;;;;;;;;;;;;;;;;;;;;;GAgE1B,KAAY,MAChB,KAAS,OAAO,KAAU,YAAY,CAAC,MAAM,QAAQ,EAAM,GAAI,IAAoC,MAE/F,KAAY,MAAmC,OAAO,KAAU,YAAY,EAAM,SAAS,IAAI,IAAQ,MAOvG,KACJ,MACuF;CACvF,IAAM,IAAW,EAAS,GAAU,SAAS,EACvC,IAAgB,EAAS,GAAU,cAAc,EACjD,IAAc,EAAS,GAAU,YAAY,EAC7C,IAAgB,EAAS,GAAU,cAAc,EAEjD,IAAU,EAAS,GAAe,QAAQ,EAC1C,IAAa,EAAS,GAAa,WAAW;AAGpD,QAAO;EACL,gBAHqB,MAAY,kBAAkB,MAAe;EAIlE,aAAa,EAAS,GAAe,KAAK,IAAI,EAAS,GAAe,YAAY;EAClF,YAAY,EAAS,GAAe,WAAW;EAChD;GAQU,KAAgC,IAAQ,OAAO;CAC1D,IAAM,EAAE,SAAM,YAAS,UAAO,eAAY,EAAgC,GAAsB;EAC9F,WAAW;GAAE;GAAO,MAAM;IAAE,OAAO;IAAmB,WAAW;IAAQ;GAAE;EAC3E,aAAa;EACd,CAAC;AAoBF,QAAO;EAAE,OAlBuC,GAAM,cAAc,SAAS,EAAE,EAC5E,KAAK,MAAS,EAAK,KAAK,CACxB,QAAQ,MAAS,EAAwB,EAAK,SAAS,CAAC,eAAe,CACvE,KAAK,MAAS;GACb,IAAM,IAAU,EAAwB,EAAK,SAAS;AACtD,UAAO;IACL,IAAI,EAAK;IACT,OAAO,EAAK,SAAS;IACrB,QAAQ,EAAK;IACb,aAAa,EAAK;IAClB,WAAW,EAAK;IAChB,iBAAiB,EAAK,aAAa,SAAS,QAAQ;IACpD,eAAe,EAAK,aAAa,aAAa;IAC9C,aAAa,EAAQ;IACrB,YAAY,EAAQ;IACrB;IACD;EAE0B;EAAS;EAAO;EAAS"}