@burdenoff/microfe-housingvista 2026.703.13 → 2026.709.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.
- package/dist/generated/global-operations.d.ts +2 -0
- package/dist/generated/global-operations.d.ts.map +1 -0
- package/dist/generated/global-types.d.ts +23527 -0
- package/dist/generated/global-types.d.ts.map +1 -0
- package/dist/generated/wspace-operations.d.ts +267 -0
- package/dist/generated/wspace-operations.d.ts.map +1 -0
- package/dist/generated/wspace-operations.js +67 -0
- package/dist/generated/wspace-operations.js.map +1 -0
- package/dist/generated/wspace-types.d.ts +57868 -0
- package/dist/generated/wspace-types.d.ts.map +1 -0
- package/dist/housingvista/HousingVistaRoot.d.ts +5 -0
- package/dist/housingvista/HousingVistaRoot.d.ts.map +1 -0
- package/dist/housingvista/HousingVistaRoutes.d.ts +7 -0
- package/dist/housingvista/HousingVistaRoutes.d.ts.map +1 -0
- package/dist/housingvista/components/Breadcrumbs.d.ts +13 -0
- package/dist/housingvista/components/Breadcrumbs.d.ts.map +1 -0
- package/dist/housingvista/components/ChartCard.d.ts +12 -0
- package/dist/housingvista/components/ChartCard.d.ts.map +1 -0
- package/dist/housingvista/components/ContactOwnerDialog.d.ts +33 -0
- package/dist/housingvista/components/ContactOwnerDialog.d.ts.map +1 -0
- package/dist/housingvista/components/DataTable.d.ts +42 -0
- package/dist/housingvista/components/DataTable.d.ts.map +1 -0
- package/dist/housingvista/components/EmptyState.d.ts +19 -0
- package/dist/housingvista/components/EmptyState.d.ts.map +1 -0
- package/dist/housingvista/components/ErrorBoundary.d.ts +19 -0
- package/dist/housingvista/components/ErrorBoundary.d.ts.map +1 -0
- package/dist/housingvista/components/FileUploader.d.ts +16 -0
- package/dist/housingvista/components/FileUploader.d.ts.map +1 -0
- package/dist/housingvista/components/FilterBar.d.ts +13 -0
- package/dist/housingvista/components/FilterBar.d.ts.map +1 -0
- package/dist/housingvista/components/LoadingSkeleton.d.ts +10 -0
- package/dist/housingvista/components/LoadingSkeleton.d.ts.map +1 -0
- package/dist/housingvista/components/PageLayout.d.ts +18 -0
- package/dist/housingvista/components/PageLayout.d.ts.map +1 -0
- package/dist/housingvista/components/PropertyCard.d.ts +26 -0
- package/dist/housingvista/components/PropertyCard.d.ts.map +1 -0
- package/dist/housingvista/components/ReviewsSection.d.ts +12 -0
- package/dist/housingvista/components/ReviewsSection.d.ts.map +1 -0
- package/dist/housingvista/components/StatCard.d.ts +18 -0
- package/dist/housingvista/components/StatCard.d.ts.map +1 -0
- package/dist/housingvista/components/StatusBadge.d.ts +12 -0
- package/dist/housingvista/components/StatusBadge.d.ts.map +1 -0
- package/dist/housingvista/components/index.d.ts +17 -0
- package/dist/housingvista/components/index.d.ts.map +1 -0
- package/dist/housingvista/context/HousingVistaContext.d.ts +15 -0
- package/dist/housingvista/context/HousingVistaContext.d.ts.map +1 -0
- package/dist/housingvista/hooks/index.d.ts +804 -0
- package/dist/housingvista/hooks/index.d.ts.map +1 -0
- package/dist/housingvista/hooks/index.js +1 -0
- package/dist/housingvista/hooks/index.js.map +1 -1
- package/dist/housingvista/hooks/messages.d.ts +65 -0
- package/dist/housingvista/hooks/messages.d.ts.map +1 -0
- package/dist/housingvista/hooks/platform.d.ts +140 -0
- package/dist/housingvista/hooks/platform.d.ts.map +1 -0
- package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts +16 -0
- package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts.map +1 -0
- package/dist/housingvista/hooks/useHousingVistaAnalytics.js +57 -0
- package/dist/housingvista/hooks/useHousingVistaAnalytics.js.map +1 -0
- package/dist/housingvista/hooks/useServerPagination.d.ts +12 -0
- package/dist/housingvista/hooks/useServerPagination.d.ts.map +1 -0
- package/dist/housingvista/index.d.ts +13 -0
- package/dist/housingvista/index.d.ts.map +1 -0
- package/dist/housingvista/index.js +2 -0
- package/dist/housingvista/lib/toast.d.ts +11 -0
- package/dist/housingvista/lib/toast.d.ts.map +1 -0
- package/dist/housingvista/pages/HomePage.d.ts +7 -0
- package/dist/housingvista/pages/HomePage.d.ts.map +1 -0
- package/dist/housingvista/pages/HomePage.js +135 -132
- package/dist/housingvista/pages/HomePage.js.map +1 -1
- package/dist/housingvista/pages/amc/AMCManagementPage.d.ts +2 -0
- package/dist/housingvista/pages/amc/AMCManagementPage.d.ts.map +1 -0
- package/dist/housingvista/pages/analytics/AnalyticsPage.d.ts +2 -0
- package/dist/housingvista/pages/analytics/AnalyticsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/analytics/AnalyticsPage.js +136 -134
- package/dist/housingvista/pages/analytics/AnalyticsPage.js.map +1 -1
- package/dist/housingvista/pages/assets/AssetDetailPage.d.ts +9 -0
- package/dist/housingvista/pages/assets/AssetDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/assets/AssetManagementPage.d.ts +2 -0
- package/dist/housingvista/pages/assets/AssetManagementPage.d.ts.map +1 -0
- package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
- package/dist/housingvista/pages/chat/ChatPage.d.ts +14 -0
- package/dist/housingvista/pages/chat/ChatPage.d.ts.map +1 -0
- package/dist/housingvista/pages/finance/HomeLoanDetailPage.d.ts +11 -0
- package/dist/housingvista/pages/finance/HomeLoanDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/finance/HomeLoansPage.d.ts +2 -0
- package/dist/housingvista/pages/finance/HomeLoansPage.d.ts.map +1 -0
- package/dist/housingvista/pages/investments/InvestmentDetailPage.d.ts +2 -0
- package/dist/housingvista/pages/investments/InvestmentDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/investments/InvestmentsPage.d.ts +2 -0
- package/dist/housingvista/pages/investments/InvestmentsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
- package/dist/housingvista/pages/legal/LegalPage.d.ts +2 -0
- package/dist/housingvista/pages/legal/LegalPage.d.ts.map +1 -0
- package/dist/housingvista/pages/legal/LegalServiceDetailPage.d.ts +12 -0
- package/dist/housingvista/pages/legal/LegalServiceDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/market/AreaInsightsPage.d.ts +2 -0
- package/dist/housingvista/pages/market/AreaInsightsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/market/MarketAnalyticsPage.d.ts +2 -0
- package/dist/housingvista/pages/market/MarketAnalyticsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/marketplace/MarketplacePage.d.ts +2 -0
- package/dist/housingvista/pages/marketplace/MarketplacePage.d.ts.map +1 -0
- package/dist/housingvista/pages/marketplace/ServiceDetailPage.d.ts +12 -0
- package/dist/housingvista/pages/marketplace/ServiceDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/offers/OffersPage.d.ts +10 -0
- package/dist/housingvista/pages/offers/OffersPage.d.ts.map +1 -0
- package/dist/housingvista/pages/properties/AddPropertyPage.d.ts +8 -0
- package/dist/housingvista/pages/properties/AddPropertyPage.d.ts.map +1 -0
- package/dist/housingvista/pages/properties/AddPropertyPage.js +279 -278
- package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.d.ts +7 -0
- package/dist/housingvista/pages/properties/PropertiesPage.d.ts.map +1 -0
- package/dist/housingvista/pages/properties/PropertiesPage.js +93 -86
- package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.d.ts +9 -0
- package/dist/housingvista/pages/properties/PropertyDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/properties/PropertyDetailPage.js +514 -511
- package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
- package/dist/housingvista/pages/rental/RentalManagementPage.d.ts +2 -0
- package/dist/housingvista/pages/rental/RentalManagementPage.d.ts.map +1 -0
- package/dist/housingvista/pages/settings/ProfilePage.d.ts +2 -0
- package/dist/housingvista/pages/settings/ProfilePage.d.ts.map +1 -0
- package/dist/housingvista/pages/settings/SettingsPage.d.ts +2 -0
- package/dist/housingvista/pages/settings/SettingsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/shortlist/ShortlistPage.d.ts +8 -0
- package/dist/housingvista/pages/shortlist/ShortlistPage.d.ts.map +1 -0
- package/dist/housingvista/pages/transactions/TransactionDetailPage.d.ts +8 -0
- package/dist/housingvista/pages/transactions/TransactionDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/transactions/TransactionsPage.d.ts +7 -0
- package/dist/housingvista/pages/transactions/TransactionsPage.d.ts.map +1 -0
- package/dist/housingvista/pages/transactions/milestones.d.ts +35 -0
- package/dist/housingvista/pages/transactions/milestones.d.ts.map +1 -0
- package/dist/housingvista/pages/verification/VerificationDetailPage.d.ts +10 -0
- package/dist/housingvista/pages/verification/VerificationDetailPage.d.ts.map +1 -0
- package/dist/housingvista/pages/verification/VerificationPage.d.ts +2 -0
- package/dist/housingvista/pages/verification/VerificationPage.d.ts.map +1 -0
- package/dist/housingvista/pages/viewings/ViewingsPage.d.ts +9 -0
- package/dist/housingvista/pages/viewings/ViewingsPage.d.ts.map +1 -0
- package/dist/housingvista/services/assistantApi.d.ts +90 -0
- package/dist/housingvista/services/assistantApi.d.ts.map +1 -0
- package/dist/housingvista/services/assistantApi.js +222 -0
- package/dist/housingvista/services/assistantApi.js.map +1 -0
- package/dist/housingvista/services/createSandboxAssistantTransport.d.ts +42 -0
- package/dist/housingvista/services/createSandboxAssistantTransport.d.ts.map +1 -0
- package/dist/housingvista/services/createSandboxAssistantTransport.js +120 -0
- package/dist/housingvista/services/createSandboxAssistantTransport.js.map +1 -0
- package/dist/housingvista/store/housingvistaStore.d.ts +72 -0
- package/dist/housingvista/store/housingvistaStore.d.ts.map +1 -0
- package/dist/housingvista/types/assistant.d.ts +16 -0
- package/dist/housingvista/types/assistant.d.ts.map +1 -0
- package/dist/housingvista/types/index.d.ts +1328 -0
- package/dist/housingvista/types/index.d.ts.map +1 -0
- package/dist/housingvista/utils/helpers.d.ts +25 -0
- package/dist/housingvista/utils/helpers.d.ts.map +1 -0
- package/dist/housingvista/utils/index.d.ts +2 -0
- package/dist/housingvista/utils/index.d.ts.map +1 -0
- package/dist/housingvista/utils/pageContext.d.ts +25 -0
- package/dist/housingvista/utils/pageContext.d.ts.map +1 -0
- package/dist/housingvista/utils/pageContext.js +77 -0
- package/dist/housingvista/utils/pageContext.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -3
- package/package.json +6 -2
|
@@ -3,24 +3,27 @@ import { PageLayout as t } from "../../components/PageLayout.js";
|
|
|
3
3
|
import { StatCard as n } from "../../components/StatCard.js";
|
|
4
4
|
import { EmptyState as r } from "../../components/EmptyState.js";
|
|
5
5
|
import { FilterBar as ee } from "../../components/FilterBar.js";
|
|
6
|
-
import { LoadingSkeleton as
|
|
7
|
-
import { PropertyCard as
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
6
|
+
import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
|
|
7
|
+
import { PropertyCard as a } from "../../components/PropertyCard.js";
|
|
8
|
+
import { useHousingVistaAnalytics as o, useTrackPageView as s } from "../../hooks/useHousingVistaAnalytics.js";
|
|
9
|
+
import { useDashboardStats as te, useProperties as ne, useRemoveShortlist as re, useSaveShortlist as ie, useShortlists as ae } from "../../hooks/index.js";
|
|
10
|
+
import { notify as c } from "../../lib/toast.js";
|
|
10
11
|
import "../../components/index.js";
|
|
11
12
|
import { useServerPagination as oe } from "../../hooks/useServerPagination.js";
|
|
12
|
-
import { useEffect as
|
|
13
|
-
import { Building as
|
|
14
|
-
import { useNavigate as
|
|
15
|
-
import { Fragment as
|
|
16
|
-
import { useI18n as
|
|
17
|
-
import { EmphasisPanel as
|
|
13
|
+
import { useEffect as l, useMemo as u, useState as d } from "react";
|
|
14
|
+
import { Building as f, Grid as p, List as m, Plus as h, SlidersHorizontal as g, X as _ } from "lucide-react";
|
|
15
|
+
import { useNavigate as se } from "react-router-dom";
|
|
16
|
+
import { Fragment as ce, jsx as v, jsxs as y } from "react/jsx-runtime";
|
|
17
|
+
import { useI18n as le } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
18
|
+
import { EmphasisPanel as ue, Pagination as de } from "@burdenoff/fe-libs/ui";
|
|
18
19
|
//#region src/housingvista/pages/properties/PropertiesPage.tsx
|
|
19
|
-
var
|
|
20
|
-
let b =
|
|
21
|
-
|
|
20
|
+
var fe = 9, b = () => {
|
|
21
|
+
let b = se(), { t: pe } = le(), { emit: me, emitResource: he, emitSearch: ge } = o();
|
|
22
|
+
s("housingvista.property.viewed");
|
|
23
|
+
let x = (e, t) => {
|
|
24
|
+
let n = pe(e);
|
|
22
25
|
return n === e ? t : n;
|
|
23
|
-
},
|
|
26
|
+
}, _e = [
|
|
24
27
|
{
|
|
25
28
|
value: "all",
|
|
26
29
|
label: x("housingvista.properties.filters.propertyTypes.all", "All Types")
|
|
@@ -45,7 +48,7 @@ var ue = 9, b = () => {
|
|
|
45
48
|
value: "mixed_use",
|
|
46
49
|
label: x("housingvista.properties.filters.propertyTypes.mixedUse", "Mixed Use")
|
|
47
50
|
}
|
|
48
|
-
],
|
|
51
|
+
], ve = [
|
|
49
52
|
{
|
|
50
53
|
value: "all",
|
|
51
54
|
label: x("housingvista.properties.filters.propertyStatuses.all", "All Status")
|
|
@@ -74,7 +77,7 @@ var ue = 9, b = () => {
|
|
|
74
77
|
value: "off_market",
|
|
75
78
|
label: x("housingvista.properties.filters.propertyStatuses.offMarket", "Off Market")
|
|
76
79
|
}
|
|
77
|
-
],
|
|
80
|
+
], ye = [
|
|
78
81
|
{
|
|
79
82
|
value: "all",
|
|
80
83
|
label: x("housingvista.properties.filters.propertyCategories.all", "All Categories")
|
|
@@ -142,7 +145,7 @@ var ue = 9, b = () => {
|
|
|
142
145
|
min: 1e6,
|
|
143
146
|
max: Infinity
|
|
144
147
|
}
|
|
145
|
-
],
|
|
148
|
+
], be = [
|
|
146
149
|
{
|
|
147
150
|
value: "all",
|
|
148
151
|
label: x("housingvista.properties.filters.bedrooms.all", "Any Bedrooms")
|
|
@@ -167,12 +170,14 @@ var ue = 9, b = () => {
|
|
|
167
170
|
value: "5",
|
|
168
171
|
label: "5+"
|
|
169
172
|
}
|
|
170
|
-
], [C, w] =
|
|
171
|
-
|
|
172
|
-
let e = setTimeout(() =>
|
|
173
|
+
], [C, w] = d(""), [T, E] = d("all"), [D, O] = d("all"), [k, A] = d("all"), [j, M] = d("all"), [N, P] = d("all"), [F, I] = d("grid"), [L, xe] = d(!1), R = S.find((e) => e.value === j) ?? S[0], z = N === "all" ? 0 : Number(N), [B, Se] = d("");
|
|
174
|
+
l(() => {
|
|
175
|
+
let e = setTimeout(() => Se(C), 300);
|
|
173
176
|
return () => clearTimeout(e);
|
|
174
|
-
}, [C])
|
|
175
|
-
|
|
177
|
+
}, [C]), l(() => {
|
|
178
|
+
B.trim() && ge("properties");
|
|
179
|
+
}, [B]);
|
|
180
|
+
let { page: V, pageSize: H, pagination: Ce, setPage: U, setPageSize: we } = oe(fe), W = u(() => {
|
|
176
181
|
let e = {};
|
|
177
182
|
return B.trim() && (e.search = B.trim()), D !== "all" && (e.status = D), T !== "all" && (e.type = T), Object.keys(e).length > 0 ? e : void 0;
|
|
178
183
|
}, [
|
|
@@ -180,19 +185,19 @@ var ue = 9, b = () => {
|
|
|
180
185
|
D,
|
|
181
186
|
T
|
|
182
187
|
]);
|
|
183
|
-
|
|
188
|
+
l(() => {
|
|
184
189
|
U(1);
|
|
185
190
|
}, [W, U]);
|
|
186
|
-
let { data: G, loading: K } =
|
|
191
|
+
let { data: G, loading: K } = ne({
|
|
187
192
|
filter: W,
|
|
188
|
-
pagination:
|
|
189
|
-
}), { data: q } =
|
|
193
|
+
pagination: Ce
|
|
194
|
+
}), { data: q } = te(), { data: J } = ae(), { saveShortlist: Te } = ie(), { removeShortlist: Ee } = re(), Y = u(() => new Set(J.map((e) => e.propertyId)), [J]), X = async (e) => {
|
|
190
195
|
try {
|
|
191
|
-
|
|
196
|
+
Y.has(e) ? (await Ee(e), c.success("Removed from shortlist")) : (await Te(e), he("housingvista.shortlist.property_added", e), c.success("Saved to shortlist"));
|
|
192
197
|
} catch (e) {
|
|
193
|
-
|
|
198
|
+
c.error("Could not update shortlist", e.message);
|
|
194
199
|
}
|
|
195
|
-
}, Z =
|
|
200
|
+
}, Z = u(() => G.filter((e) => {
|
|
196
201
|
let t = k === "all" || e.category === k, n = e.price.amount >= R.min && e.price.amount <= R.max, r = (e.specifications.bedrooms ?? 0) >= z;
|
|
197
202
|
return t && n && r;
|
|
198
203
|
}), [
|
|
@@ -200,40 +205,42 @@ var ue = 9, b = () => {
|
|
|
200
205
|
k,
|
|
201
206
|
R,
|
|
202
207
|
z
|
|
203
|
-
]),
|
|
208
|
+
]), De = G.length >= H, Q = C || T !== "all" || D !== "all" || k !== "all" || j !== "all" || N !== "all", $ = () => {
|
|
204
209
|
w(""), E("all"), O("all"), A("all"), M("all"), P("all");
|
|
205
210
|
};
|
|
206
|
-
return /* @__PURE__ */
|
|
211
|
+
return /* @__PURE__ */ y(t, {
|
|
207
212
|
title: x("housingvista.properties.title", "Properties"),
|
|
208
213
|
description: x("housingvista.properties.description", "Discover your perfect property from our comprehensive listings"),
|
|
209
214
|
purpose: x("housingvista.properties.purpose", "Browse, search, and filter every property in your portfolio or on the market. Use the filters to narrow by type, status, price, and bedrooms, then open any listing to see full details, schedule viewings, or start a transaction."),
|
|
210
|
-
actions: /* @__PURE__ */
|
|
211
|
-
onClick: () =>
|
|
215
|
+
actions: /* @__PURE__ */ y("button", {
|
|
216
|
+
onClick: () => {
|
|
217
|
+
me("housingvista.property.create_clicked"), b("new");
|
|
218
|
+
},
|
|
212
219
|
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",
|
|
213
|
-
children: [/* @__PURE__ */
|
|
220
|
+
children: [/* @__PURE__ */ v(h, { className: "h-4 w-4" }), x("housingvista.properties.actions.addProperty", "Add Property")]
|
|
214
221
|
}),
|
|
215
222
|
children: [
|
|
216
|
-
/* @__PURE__ */
|
|
223
|
+
/* @__PURE__ */ v(ue, {
|
|
217
224
|
className: "p-4",
|
|
218
|
-
children: /* @__PURE__ */
|
|
225
|
+
children: /* @__PURE__ */ y("div", {
|
|
219
226
|
className: "grid grid-cols-2 gap-4 lg:grid-cols-4",
|
|
220
227
|
children: [
|
|
221
|
-
/* @__PURE__ */
|
|
228
|
+
/* @__PURE__ */ v(n, {
|
|
222
229
|
label: x("housingvista.properties.stats.totalProperties", "Total Properties"),
|
|
223
230
|
value: q.totalProperties,
|
|
224
|
-
icon: /* @__PURE__ */
|
|
231
|
+
icon: /* @__PURE__ */ v(f, { className: "h-5 w-5" })
|
|
225
232
|
}),
|
|
226
|
-
/* @__PURE__ */
|
|
233
|
+
/* @__PURE__ */ v(n, {
|
|
227
234
|
label: x("housingvista.properties.stats.portfolioValue", "Portfolio Value"),
|
|
228
235
|
value: q.totalValue,
|
|
229
236
|
prefix: "$"
|
|
230
237
|
}),
|
|
231
|
-
/* @__PURE__ */
|
|
238
|
+
/* @__PURE__ */ v(n, {
|
|
232
239
|
label: x("housingvista.properties.stats.occupancyRate", "Occupancy Rate"),
|
|
233
240
|
value: q.occupancyRate,
|
|
234
241
|
unit: "%"
|
|
235
242
|
}),
|
|
236
|
-
/* @__PURE__ */
|
|
243
|
+
/* @__PURE__ */ v(n, {
|
|
237
244
|
label: x("housingvista.properties.stats.monthlyRevenue", "Monthly Revenue"),
|
|
238
245
|
value: q.monthlyRevenue,
|
|
239
246
|
prefix: "$"
|
|
@@ -241,106 +248,106 @@ var ue = 9, b = () => {
|
|
|
241
248
|
]
|
|
242
249
|
})
|
|
243
250
|
}),
|
|
244
|
-
/* @__PURE__ */
|
|
251
|
+
/* @__PURE__ */ v(ee, {
|
|
245
252
|
searchValue: C,
|
|
246
253
|
onSearchChange: w,
|
|
247
254
|
searchPlaceholder: x("housingvista.properties.search.placeholder", "Search properties by name, city, or neighborhood..."),
|
|
248
|
-
filters: /* @__PURE__ */
|
|
249
|
-
onClick: () =>
|
|
255
|
+
filters: /* @__PURE__ */ y("button", {
|
|
256
|
+
onClick: () => xe((e) => !e),
|
|
250
257
|
className: e("inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium transition-colors", L ? "bg-foreground text-background" : "text-text-primary hover:bg-bg-sunken"),
|
|
251
258
|
children: [
|
|
252
|
-
/* @__PURE__ */ g
|
|
259
|
+
/* @__PURE__ */ v(g, { className: "h-4 w-4" }),
|
|
253
260
|
x("housingvista.properties.filters.toggle", "Filters"),
|
|
254
|
-
Q && /* @__PURE__ */
|
|
261
|
+
Q && /* @__PURE__ */ v("span", {
|
|
255
262
|
className: "flex h-5 w-5 items-center justify-center rounded-full bg-action-primary-bg text-[10px] font-bold text-action-primary-text",
|
|
256
263
|
children: "!"
|
|
257
264
|
})
|
|
258
265
|
]
|
|
259
266
|
}),
|
|
260
|
-
actions: /* @__PURE__ */
|
|
267
|
+
actions: /* @__PURE__ */ y("div", {
|
|
261
268
|
className: "flex items-center gap-1",
|
|
262
|
-
children: [/* @__PURE__ */
|
|
269
|
+
children: [/* @__PURE__ */ v("button", {
|
|
263
270
|
onClick: () => I("grid"),
|
|
264
271
|
className: e("rounded-md p-2 transition-colors", F === "grid" ? "bg-foreground text-background" : "text-text-secondary hover:text-text-primary hover:bg-bg-sunken"),
|
|
265
|
-
children: /* @__PURE__ */
|
|
266
|
-
}), /* @__PURE__ */
|
|
272
|
+
children: /* @__PURE__ */ v(p, { className: "h-4 w-4" })
|
|
273
|
+
}), /* @__PURE__ */ v("button", {
|
|
267
274
|
onClick: () => I("list"),
|
|
268
275
|
className: e("rounded-md p-2 transition-colors", F === "list" ? "bg-foreground text-background" : "text-text-secondary hover:text-text-primary hover:bg-bg-sunken"),
|
|
269
|
-
children: /* @__PURE__ */
|
|
276
|
+
children: /* @__PURE__ */ v(m, { className: "h-4 w-4" })
|
|
270
277
|
})]
|
|
271
278
|
})
|
|
272
279
|
}),
|
|
273
|
-
L && /* @__PURE__ */
|
|
280
|
+
L && /* @__PURE__ */ y("div", {
|
|
274
281
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-4",
|
|
275
|
-
children: [/* @__PURE__ */
|
|
282
|
+
children: [/* @__PURE__ */ y("div", {
|
|
276
283
|
className: "flex items-center justify-between mb-4",
|
|
277
|
-
children: [/* @__PURE__ */
|
|
284
|
+
children: [/* @__PURE__ */ v("h3", {
|
|
278
285
|
className: "text-sm font-medium text-text-primary",
|
|
279
286
|
children: x("housingvista.properties.filters.title", "Filters")
|
|
280
|
-
}), Q && /* @__PURE__ */
|
|
287
|
+
}), Q && /* @__PURE__ */ y("button", {
|
|
281
288
|
onClick: $,
|
|
282
289
|
className: "inline-flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary",
|
|
283
|
-
children: [/* @__PURE__ */
|
|
290
|
+
children: [/* @__PURE__ */ v(_, { className: "h-3 w-3" }), x("housingvista.properties.filters.clearAll", "Clear All")]
|
|
284
291
|
})]
|
|
285
|
-
}), /* @__PURE__ */
|
|
292
|
+
}), /* @__PURE__ */ y("div", {
|
|
286
293
|
className: "grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5",
|
|
287
294
|
children: [
|
|
288
|
-
/* @__PURE__ */
|
|
295
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
289
296
|
className: "mb-1.5 block text-xs font-medium text-text-secondary",
|
|
290
297
|
children: x("housingvista.properties.filters.labels.propertyType", "Property Type")
|
|
291
|
-
}), /* @__PURE__ */
|
|
298
|
+
}), /* @__PURE__ */ v("select", {
|
|
292
299
|
value: T,
|
|
293
300
|
onChange: (e) => E(e.target.value),
|
|
294
301
|
className: "h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
295
|
-
children:
|
|
302
|
+
children: _e.map((e) => /* @__PURE__ */ v("option", {
|
|
296
303
|
value: e.value,
|
|
297
304
|
children: e.label
|
|
298
305
|
}, e.value))
|
|
299
306
|
})] }),
|
|
300
|
-
/* @__PURE__ */
|
|
307
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
301
308
|
className: "mb-1.5 block text-xs font-medium text-text-secondary",
|
|
302
309
|
children: x("housingvista.properties.filters.labels.status", "Status")
|
|
303
|
-
}), /* @__PURE__ */
|
|
310
|
+
}), /* @__PURE__ */ v("select", {
|
|
304
311
|
value: D,
|
|
305
312
|
onChange: (e) => O(e.target.value),
|
|
306
313
|
className: "h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
307
|
-
children:
|
|
314
|
+
children: ve.map((e) => /* @__PURE__ */ v("option", {
|
|
308
315
|
value: e.value,
|
|
309
316
|
children: e.label
|
|
310
317
|
}, e.value))
|
|
311
318
|
})] }),
|
|
312
|
-
/* @__PURE__ */
|
|
319
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
313
320
|
className: "mb-1.5 block text-xs font-medium text-text-secondary",
|
|
314
321
|
children: x("housingvista.properties.filters.labels.category", "Category")
|
|
315
|
-
}), /* @__PURE__ */
|
|
322
|
+
}), /* @__PURE__ */ v("select", {
|
|
316
323
|
value: k,
|
|
317
324
|
onChange: (e) => A(e.target.value),
|
|
318
325
|
className: "h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
319
|
-
children:
|
|
326
|
+
children: ye.map((e) => /* @__PURE__ */ v("option", {
|
|
320
327
|
value: e.value,
|
|
321
328
|
children: e.label
|
|
322
329
|
}, e.value))
|
|
323
330
|
})] }),
|
|
324
|
-
/* @__PURE__ */
|
|
331
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
325
332
|
className: "mb-1.5 block text-xs font-medium text-text-secondary",
|
|
326
333
|
children: x("housingvista.properties.filters.labels.priceRange", "Price Range")
|
|
327
|
-
}), /* @__PURE__ */
|
|
334
|
+
}), /* @__PURE__ */ v("select", {
|
|
328
335
|
value: j,
|
|
329
336
|
onChange: (e) => M(e.target.value),
|
|
330
337
|
className: "h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
331
|
-
children: S.map((e) => /* @__PURE__ */
|
|
338
|
+
children: S.map((e) => /* @__PURE__ */ v("option", {
|
|
332
339
|
value: e.value,
|
|
333
340
|
children: e.label
|
|
334
341
|
}, e.value))
|
|
335
342
|
})] }),
|
|
336
|
-
/* @__PURE__ */
|
|
343
|
+
/* @__PURE__ */ y("div", { children: [/* @__PURE__ */ v("label", {
|
|
337
344
|
className: "mb-1.5 block text-xs font-medium text-text-secondary",
|
|
338
345
|
children: x("housingvista.properties.filters.labels.bedrooms", "Bedrooms")
|
|
339
|
-
}), /* @__PURE__ */
|
|
346
|
+
}), /* @__PURE__ */ v("select", {
|
|
340
347
|
value: N,
|
|
341
348
|
onChange: (e) => P(e.target.value),
|
|
342
349
|
className: "h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]",
|
|
343
|
-
children:
|
|
350
|
+
children: be.map((e) => /* @__PURE__ */ v("option", {
|
|
344
351
|
value: e.value,
|
|
345
352
|
children: e.label
|
|
346
353
|
}, e.value))
|
|
@@ -348,9 +355,9 @@ var ue = 9, b = () => {
|
|
|
348
355
|
]
|
|
349
356
|
})]
|
|
350
357
|
}),
|
|
351
|
-
/* @__PURE__ */
|
|
358
|
+
/* @__PURE__ */ y("div", {
|
|
352
359
|
className: "flex items-center justify-between",
|
|
353
|
-
children: [/* @__PURE__ */
|
|
360
|
+
children: [/* @__PURE__ */ y("p", {
|
|
354
361
|
className: "text-sm text-text-secondary",
|
|
355
362
|
children: [
|
|
356
363
|
x("housingvista.properties.results.showing", "Showing"),
|
|
@@ -360,18 +367,18 @@ var ue = 9, b = () => {
|
|
|
360
367
|
x("housingvista.properties.results.properties", "properties"),
|
|
361
368
|
V > 1 ? ` · page ${V}` : ""
|
|
362
369
|
]
|
|
363
|
-
}), Q && /* @__PURE__ */
|
|
370
|
+
}), Q && /* @__PURE__ */ v("button", {
|
|
364
371
|
onClick: $,
|
|
365
372
|
className: "text-sm text-text-secondary hover:text-text-primary",
|
|
366
373
|
children: x("housingvista.properties.results.clearFilters", "Clear Filters")
|
|
367
374
|
})]
|
|
368
375
|
}),
|
|
369
|
-
K ? /* @__PURE__ */
|
|
376
|
+
K ? /* @__PURE__ */ v(i, {
|
|
370
377
|
variant: "card",
|
|
371
378
|
count: 6
|
|
372
|
-
}) : Z.length > 0 ? /* @__PURE__ */
|
|
379
|
+
}) : Z.length > 0 ? /* @__PURE__ */ y(ce, { children: [/* @__PURE__ */ v("div", {
|
|
373
380
|
className: e(F === "grid" ? "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3" : "space-y-4"),
|
|
374
|
-
children: Z.map((e) => /* @__PURE__ */
|
|
381
|
+
children: Z.map((e) => /* @__PURE__ */ v(a, {
|
|
375
382
|
id: e.id,
|
|
376
383
|
title: e.title,
|
|
377
384
|
price: e.price.amount,
|
|
@@ -386,23 +393,23 @@ var ue = 9, b = () => {
|
|
|
386
393
|
status: e.status.replace("_", " "),
|
|
387
394
|
type: e.category,
|
|
388
395
|
onClick: () => b(e.id),
|
|
389
|
-
isShortlisted:
|
|
390
|
-
onToggleShortlist: () =>
|
|
396
|
+
isShortlisted: Y.has(e.id),
|
|
397
|
+
onToggleShortlist: () => X(e.id)
|
|
391
398
|
}, e.id))
|
|
392
|
-
}), /* @__PURE__ */
|
|
399
|
+
}), /* @__PURE__ */ v(de, {
|
|
393
400
|
page: V,
|
|
394
401
|
pageSize: H,
|
|
395
|
-
hasNextPage:
|
|
402
|
+
hasNextPage: De,
|
|
396
403
|
hasPreviousPage: V > 1,
|
|
397
404
|
loading: K,
|
|
398
405
|
onPageChange: U,
|
|
399
|
-
onPageSizeChange:
|
|
400
|
-
})] }) : /* @__PURE__ */
|
|
406
|
+
onPageSizeChange: we
|
|
407
|
+
})] }) : /* @__PURE__ */ v(r, {
|
|
401
408
|
illustration: "empty-search",
|
|
402
|
-
icon: /* @__PURE__ */
|
|
409
|
+
icon: /* @__PURE__ */ v(f, { className: "h-12 w-12" }),
|
|
403
410
|
title: x("housingvista.properties.empty.title", "No properties found"),
|
|
404
411
|
description: x("housingvista.properties.empty.description", "Try adjusting your search criteria or filters to find more properties."),
|
|
405
|
-
action: /* @__PURE__ */
|
|
412
|
+
action: /* @__PURE__ */ v("button", {
|
|
406
413
|
onClick: $,
|
|
407
414
|
className: "rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90",
|
|
408
415
|
children: x("housingvista.properties.empty.clearAllFilters", "Clear All Filters")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PropertiesPage.js","names":[],"sources":["../../../../src/housingvista/pages/properties/PropertiesPage.tsx"],"sourcesContent":["/**\n * HousingVista Properties Listing Page\n * Migrated from legacy housingvista-frontend properties.tsx\n * @module housingvista\n */\n\nimport { useState, useMemo, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Plus, Grid, List, Building, SlidersHorizontal, X } from 'lucide-react';\nimport { EmphasisPanel, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, PropertyCard, EmptyState, StatCard, LoadingSkeleton } from '../../components';\nimport {\n useProperties,\n useShortlists,\n useSaveShortlist,\n useRemoveShortlist,\n useDashboardStats,\n type PropertyFilterInput,\n} from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { cn } from '../../utils/helpers';\nimport type { PropertyType, PropertyStatus, PropertyCategory } from '../../types';\n\nconst PAGE_SIZE = 9;\n\nexport const PropertiesPage = () => {\n const navigate = useNavigate();\n const { t } = useI18n();\n\n const tr = (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const propertyTypes: { value: PropertyType | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyTypes.all', 'All Types') },\n { value: 'residential', label: tr('housingvista.properties.filters.propertyTypes.residential', 'Residential') },\n { value: 'commercial', label: tr('housingvista.properties.filters.propertyTypes.commercial', 'Commercial') },\n { value: 'industrial', label: tr('housingvista.properties.filters.propertyTypes.industrial', 'Industrial') },\n { value: 'agricultural', label: tr('housingvista.properties.filters.propertyTypes.agricultural', 'Agricultural') },\n { value: 'mixed_use', label: tr('housingvista.properties.filters.propertyTypes.mixedUse', 'Mixed Use') },\n ];\n\n const propertyStatuses: { value: PropertyStatus | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyStatuses.all', 'All Status') },\n { value: 'for_sale', label: tr('housingvista.properties.filters.propertyStatuses.forSale', 'For Sale') },\n { value: 'for_rent', label: tr('housingvista.properties.filters.propertyStatuses.forRent', 'For Rent') },\n { value: 'sold', label: tr('housingvista.properties.filters.propertyStatuses.sold', 'Sold') },\n { value: 'rented', label: tr('housingvista.properties.filters.propertyStatuses.rented', 'Rented') },\n {\n value: 'under_contract',\n label: tr('housingvista.properties.filters.propertyStatuses.underContract', 'Under Contract'),\n },\n { value: 'off_market', label: tr('housingvista.properties.filters.propertyStatuses.offMarket', 'Off Market') },\n ];\n\n const propertyCategories: { value: PropertyCategory | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyCategories.all', 'All Categories') },\n { value: 'apartment', label: tr('housingvista.properties.filters.propertyCategories.apartment', 'Apartment') },\n { value: 'house', label: tr('housingvista.properties.filters.propertyCategories.house', 'House') },\n { value: 'villa', label: tr('housingvista.properties.filters.propertyCategories.villa', 'Villa') },\n { value: 'office', label: tr('housingvista.properties.filters.propertyCategories.office', 'Office') },\n { value: 'retail', label: tr('housingvista.properties.filters.propertyCategories.retail', 'Retail') },\n { value: 'warehouse', label: tr('housingvista.properties.filters.propertyCategories.warehouse', 'Warehouse') },\n { value: 'land', label: tr('housingvista.properties.filters.propertyCategories.land', 'Land') },\n { value: 'plot', label: tr('housingvista.properties.filters.propertyCategories.plot', 'Plot') },\n ];\n\n const priceRanges = [\n { value: 'all', label: tr('housingvista.properties.filters.priceRanges.all', 'Any Price'), min: 0, max: Infinity },\n {\n value: 'under_100k',\n label: tr('housingvista.properties.filters.priceRanges.under100k', 'Under $100K'),\n min: 0,\n max: 100000,\n },\n {\n value: '100k_500k',\n label: tr('housingvista.properties.filters.priceRanges.100kTo500k', '$100K - $500K'),\n min: 100000,\n max: 500000,\n },\n {\n value: '500k_1m',\n label: tr('housingvista.properties.filters.priceRanges.500kTo1m', '$500K - $1M'),\n min: 500000,\n max: 1000000,\n },\n {\n value: 'over_1m',\n label: tr('housingvista.properties.filters.priceRanges.over1m', 'Over $1M'),\n min: 1000000,\n max: Infinity,\n },\n ];\n\n const bedroomOptions = [\n { value: 'all', label: tr('housingvista.properties.filters.bedrooms.all', 'Any Bedrooms') },\n { value: '1', label: '1+' },\n { value: '2', label: '2+' },\n { value: '3', label: '3+' },\n { value: '4', label: '4+' },\n { value: '5', label: '5+' },\n ];\n\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedType, setSelectedType] = useState<PropertyType | 'all'>('all');\n const [selectedStatus, setSelectedStatus] = useState<PropertyStatus | 'all'>('all');\n const [selectedCategory, setSelectedCategory] = useState<PropertyCategory | 'all'>('all');\n const [selectedPriceRange, setSelectedPriceRange] = useState('all');\n const [selectedBedrooms, setSelectedBedrooms] = useState('all');\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n const [showFilters, setShowFilters] = useState(false);\n\n const priceRange = priceRanges.find((r) => r.value === selectedPriceRange) ?? priceRanges[0];\n const minBedrooms = selectedBedrooms === 'all' ? 0 : Number(selectedBedrooms);\n\n // Debounce the search box so we don't refetch on every keystroke.\n const [debouncedSearch, setDebouncedSearch] = useState('');\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(searchQuery), 300);\n return () => clearTimeout(timer);\n }, [searchQuery]);\n\n const { page, pageSize, pagination, setPage, setPageSize } = useServerPagination(PAGE_SIZE);\n\n // Server-side filter uses the schema-supported fields (search/status/type).\n const serverFilter = useMemo<PropertyFilterInput | undefined>(() => {\n const filter: PropertyFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (selectedStatus !== 'all') filter.status = selectedStatus;\n if (selectedType !== 'all') filter.type = selectedType;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, selectedStatus, selectedType]);\n\n // Reset to first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: properties, loading } = useProperties({ filter: serverFilter, pagination });\n // Portfolio-wide totals for the stats zone — independent of the current page slice.\n const { data: dashboardStats } = useDashboardStats();\n const { data: shortlists } = useShortlists();\n const { saveShortlist } = useSaveShortlist();\n const { removeShortlist } = useRemoveShortlist();\n\n const shortlistedIds = useMemo(() => new Set(shortlists.map((s) => s.propertyId)), [shortlists]);\n\n const toggleShortlist = async (propertyId: string) => {\n try {\n if (shortlistedIds.has(propertyId)) {\n await removeShortlist(propertyId);\n notify.success('Removed from shortlist');\n } else {\n await saveShortlist(propertyId);\n notify.success('Saved to shortlist');\n }\n } catch (err) {\n notify.error('Could not update shortlist', (err as Error).message);\n }\n };\n\n // Category, price range, and bedrooms are refined on the client (the subgraph\n // filter input does not model them).\n const filteredProperties = useMemo(() => {\n return properties.filter((property) => {\n const matchesCategory = selectedCategory === 'all' || property.category === selectedCategory;\n const matchesPrice = property.price.amount >= priceRange.min && property.price.amount <= priceRange.max;\n const matchesBedrooms = (property.specifications.bedrooms ?? 0) >= minBedrooms;\n return matchesCategory && matchesPrice && matchesBedrooms;\n });\n }, [properties, selectedCategory, priceRange, minBedrooms]);\n\n const hasNextPage = properties.length >= pageSize;\n\n const hasActiveFilters =\n searchQuery ||\n selectedType !== 'all' ||\n selectedStatus !== 'all' ||\n selectedCategory !== 'all' ||\n selectedPriceRange !== 'all' ||\n selectedBedrooms !== 'all';\n\n const clearFilters = () => {\n setSearchQuery('');\n setSelectedType('all');\n setSelectedStatus('all');\n setSelectedCategory('all');\n setSelectedPriceRange('all');\n setSelectedBedrooms('all');\n };\n\n return (\n <PageLayout\n title={tr('housingvista.properties.title', 'Properties')}\n description={tr(\n 'housingvista.properties.description',\n 'Discover your perfect property from our comprehensive listings'\n )}\n purpose={tr(\n 'housingvista.properties.purpose',\n 'Browse, search, and filter every property in your portfolio or on the market. Use the filters to narrow by type, status, price, and bedrooms, then open any listing to see full details, schedule viewings, or start a transaction.'\n )}\n actions={\n <button\n onClick={() => navigate('new')}\n 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 >\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.properties.actions.addProperty', 'Add Property')}\n </button>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.properties.stats.totalProperties', 'Total Properties')}\n value={dashboardStats.totalProperties}\n icon={<Building className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.properties.stats.portfolioValue', 'Portfolio Value')}\n value={dashboardStats.totalValue}\n prefix=\"$\"\n />\n <StatCard\n label={tr('housingvista.properties.stats.occupancyRate', 'Occupancy Rate')}\n value={dashboardStats.occupancyRate}\n unit=\"%\"\n />\n <StatCard\n label={tr('housingvista.properties.stats.monthlyRevenue', 'Monthly Revenue')}\n value={dashboardStats.monthlyRevenue}\n prefix=\"$\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Search + View Toggle */}\n <FilterBar\n searchValue={searchQuery}\n onSearchChange={setSearchQuery}\n searchPlaceholder={tr(\n 'housingvista.properties.search.placeholder',\n 'Search properties by name, city, or neighborhood...'\n )}\n filters={\n <button\n onClick={() => setShowFilters((prev) => !prev)}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium transition-colors',\n showFilters ? 'bg-foreground text-background' : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n {tr('housingvista.properties.filters.toggle', 'Filters')}\n {hasActiveFilters && (\n <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-action-primary-bg text-[10px] font-bold text-action-primary-text\">\n !\n </span>\n )}\n </button>\n }\n actions={\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => setViewMode('grid')}\n className={cn(\n 'rounded-md p-2 transition-colors',\n viewMode === 'grid'\n ? 'bg-foreground text-background'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-sunken'\n )}\n >\n <Grid className=\"h-4 w-4\" />\n </button>\n <button\n onClick={() => setViewMode('list')}\n className={cn(\n 'rounded-md p-2 transition-colors',\n viewMode === 'list'\n ? 'bg-foreground text-background'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-sunken'\n )}\n >\n <List className=\"h-4 w-4\" />\n </button>\n </div>\n }\n />\n\n {/* Filter Dropdowns */}\n {showFilters && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">\n {tr('housingvista.properties.filters.title', 'Filters')}\n </h3>\n {hasActiveFilters && (\n <button\n onClick={clearFilters}\n className=\"inline-flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-3 w-3\" />\n {tr('housingvista.properties.filters.clearAll', 'Clear All')}\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5\">\n {/* Type */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.propertyType', 'Property Type')}\n </label>\n <select\n value={selectedType}\n onChange={(e) => setSelectedType(e.target.value as PropertyType | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Status */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.status', 'Status')}\n </label>\n <select\n value={selectedStatus}\n onChange={(e) => setSelectedStatus(e.target.value as PropertyStatus | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyStatuses.map((s) => (\n <option key={s.value} value={s.value}>\n {s.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Category */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.category', 'Category')}\n </label>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as PropertyCategory | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyCategories.map((c) => (\n <option key={c.value} value={c.value}>\n {c.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Price Range */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.priceRange', 'Price Range')}\n </label>\n <select\n value={selectedPriceRange}\n onChange={(e) => setSelectedPriceRange(e.target.value)}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {priceRanges.map((r) => (\n <option key={r.value} value={r.value}>\n {r.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Bedrooms */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.bedrooms', 'Bedrooms')}\n </label>\n <select\n value={selectedBedrooms}\n onChange={(e) => setSelectedBedrooms(e.target.value)}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {bedroomOptions.map((b) => (\n <option key={b.value} value={b.value}>\n {b.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Results Count */}\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {tr('housingvista.properties.results.showing', 'Showing')} {filteredProperties.length}{' '}\n {tr('housingvista.properties.results.properties', 'properties')}\n {page > 1 ? ` · page ${page}` : ''}\n </p>\n {hasActiveFilters && (\n <button onClick={clearFilters} className=\"text-sm text-text-secondary hover:text-text-primary\">\n {tr('housingvista.properties.results.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n\n {/* Property Grid / List */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : filteredProperties.length > 0 ? (\n <>\n <div\n className={cn(viewMode === 'grid' ? 'grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3' : 'space-y-4')}\n >\n {filteredProperties.map((property) => (\n <PropertyCard\n key={property.id}\n id={property.id}\n title={property.title}\n price={property.price.amount}\n priceType={property.price.type === 'rent' ? 'rent' : 'sale'}\n pricePeriod={property.price.period}\n currency={property.price.currency}\n location={[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n bedrooms={property.specifications.bedrooms}\n bathrooms={property.specifications.bathrooms}\n area={property.specifications.totalArea}\n imageUrl={property.images[0]?.url}\n status={property.status.replace('_', ' ')}\n type={property.category}\n onClick={() => navigate(property.id)}\n isShortlisted={shortlistedIds.has(property.id)}\n onToggleShortlist={() => toggleShortlist(property.id)}\n />\n ))}\n </div>\n\n {/* Pagination (server-side): working prev/next + page-size, no silent truncation */}\n <Pagination\n page={page}\n pageSize={pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={page > 1}\n loading={loading}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Building className=\"h-12 w-12\" />}\n title={tr('housingvista.properties.empty.title', 'No properties found')}\n description={tr(\n 'housingvista.properties.empty.description',\n 'Try adjusting your search criteria or filters to find more properties.'\n )}\n action={\n <button\n onClick={clearFilters}\n className=\"rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90\"\n >\n {tr('housingvista.properties.empty.clearAllFilters', 'Clear All Filters')}\n </button>\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"PropertiesPage.js","names":[],"sources":["../../../../src/housingvista/pages/properties/PropertiesPage.tsx"],"sourcesContent":["/**\n * HousingVista Properties Listing Page\n * Migrated from legacy housingvista-frontend properties.tsx\n * @module housingvista\n */\n\nimport { useState, useMemo, useEffect } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Plus, Grid, List, Building, SlidersHorizontal, X } from 'lucide-react';\nimport { EmphasisPanel, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, PropertyCard, EmptyState, StatCard, LoadingSkeleton } from '../../components';\nimport {\n useProperties,\n useShortlists,\n useSaveShortlist,\n useRemoveShortlist,\n useDashboardStats,\n type PropertyFilterInput,\n} from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { useHousingVistaAnalytics, useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\nimport { notify } from '../../lib/toast';\nimport { cn } from '../../utils/helpers';\nimport type { PropertyType, PropertyStatus, PropertyCategory } from '../../types';\n\nconst PAGE_SIZE = 9;\n\nexport const PropertiesPage = () => {\n const navigate = useNavigate();\n const { t } = useI18n();\n const { emit, emitResource, emitSearch } = useHousingVistaAnalytics();\n useTrackPageView('housingvista.property.viewed');\n\n const tr = (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const propertyTypes: { value: PropertyType | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyTypes.all', 'All Types') },\n { value: 'residential', label: tr('housingvista.properties.filters.propertyTypes.residential', 'Residential') },\n { value: 'commercial', label: tr('housingvista.properties.filters.propertyTypes.commercial', 'Commercial') },\n { value: 'industrial', label: tr('housingvista.properties.filters.propertyTypes.industrial', 'Industrial') },\n { value: 'agricultural', label: tr('housingvista.properties.filters.propertyTypes.agricultural', 'Agricultural') },\n { value: 'mixed_use', label: tr('housingvista.properties.filters.propertyTypes.mixedUse', 'Mixed Use') },\n ];\n\n const propertyStatuses: { value: PropertyStatus | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyStatuses.all', 'All Status') },\n { value: 'for_sale', label: tr('housingvista.properties.filters.propertyStatuses.forSale', 'For Sale') },\n { value: 'for_rent', label: tr('housingvista.properties.filters.propertyStatuses.forRent', 'For Rent') },\n { value: 'sold', label: tr('housingvista.properties.filters.propertyStatuses.sold', 'Sold') },\n { value: 'rented', label: tr('housingvista.properties.filters.propertyStatuses.rented', 'Rented') },\n {\n value: 'under_contract',\n label: tr('housingvista.properties.filters.propertyStatuses.underContract', 'Under Contract'),\n },\n { value: 'off_market', label: tr('housingvista.properties.filters.propertyStatuses.offMarket', 'Off Market') },\n ];\n\n const propertyCategories: { value: PropertyCategory | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.properties.filters.propertyCategories.all', 'All Categories') },\n { value: 'apartment', label: tr('housingvista.properties.filters.propertyCategories.apartment', 'Apartment') },\n { value: 'house', label: tr('housingvista.properties.filters.propertyCategories.house', 'House') },\n { value: 'villa', label: tr('housingvista.properties.filters.propertyCategories.villa', 'Villa') },\n { value: 'office', label: tr('housingvista.properties.filters.propertyCategories.office', 'Office') },\n { value: 'retail', label: tr('housingvista.properties.filters.propertyCategories.retail', 'Retail') },\n { value: 'warehouse', label: tr('housingvista.properties.filters.propertyCategories.warehouse', 'Warehouse') },\n { value: 'land', label: tr('housingvista.properties.filters.propertyCategories.land', 'Land') },\n { value: 'plot', label: tr('housingvista.properties.filters.propertyCategories.plot', 'Plot') },\n ];\n\n const priceRanges = [\n { value: 'all', label: tr('housingvista.properties.filters.priceRanges.all', 'Any Price'), min: 0, max: Infinity },\n {\n value: 'under_100k',\n label: tr('housingvista.properties.filters.priceRanges.under100k', 'Under $100K'),\n min: 0,\n max: 100000,\n },\n {\n value: '100k_500k',\n label: tr('housingvista.properties.filters.priceRanges.100kTo500k', '$100K - $500K'),\n min: 100000,\n max: 500000,\n },\n {\n value: '500k_1m',\n label: tr('housingvista.properties.filters.priceRanges.500kTo1m', '$500K - $1M'),\n min: 500000,\n max: 1000000,\n },\n {\n value: 'over_1m',\n label: tr('housingvista.properties.filters.priceRanges.over1m', 'Over $1M'),\n min: 1000000,\n max: Infinity,\n },\n ];\n\n const bedroomOptions = [\n { value: 'all', label: tr('housingvista.properties.filters.bedrooms.all', 'Any Bedrooms') },\n { value: '1', label: '1+' },\n { value: '2', label: '2+' },\n { value: '3', label: '3+' },\n { value: '4', label: '4+' },\n { value: '5', label: '5+' },\n ];\n\n const [searchQuery, setSearchQuery] = useState('');\n const [selectedType, setSelectedType] = useState<PropertyType | 'all'>('all');\n const [selectedStatus, setSelectedStatus] = useState<PropertyStatus | 'all'>('all');\n const [selectedCategory, setSelectedCategory] = useState<PropertyCategory | 'all'>('all');\n const [selectedPriceRange, setSelectedPriceRange] = useState('all');\n const [selectedBedrooms, setSelectedBedrooms] = useState('all');\n const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');\n const [showFilters, setShowFilters] = useState(false);\n\n const priceRange = priceRanges.find((r) => r.value === selectedPriceRange) ?? priceRanges[0];\n const minBedrooms = selectedBedrooms === 'all' ? 0 : Number(selectedBedrooms);\n\n // Debounce the search box so we don't refetch on every keystroke.\n const [debouncedSearch, setDebouncedSearch] = useState('');\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(searchQuery), 300);\n return () => clearTimeout(timer);\n }, [searchQuery]);\n\n // Analytics: emit search event when a non-empty debounced query is entered.\n useEffect(() => {\n if (debouncedSearch.trim()) {\n emitSearch('properties');\n }\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [debouncedSearch]);\n\n const { page, pageSize, pagination, setPage, setPageSize } = useServerPagination(PAGE_SIZE);\n\n // Server-side filter uses the schema-supported fields (search/status/type).\n const serverFilter = useMemo<PropertyFilterInput | undefined>(() => {\n const filter: PropertyFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (selectedStatus !== 'all') filter.status = selectedStatus;\n if (selectedType !== 'all') filter.type = selectedType;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, selectedStatus, selectedType]);\n\n // Reset to first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: properties, loading } = useProperties({ filter: serverFilter, pagination });\n // Portfolio-wide totals for the stats zone — independent of the current page slice.\n const { data: dashboardStats } = useDashboardStats();\n const { data: shortlists } = useShortlists();\n const { saveShortlist } = useSaveShortlist();\n const { removeShortlist } = useRemoveShortlist();\n\n const shortlistedIds = useMemo(() => new Set(shortlists.map((s) => s.propertyId)), [shortlists]);\n\n const toggleShortlist = async (propertyId: string) => {\n try {\n if (shortlistedIds.has(propertyId)) {\n await removeShortlist(propertyId);\n notify.success('Removed from shortlist');\n } else {\n await saveShortlist(propertyId);\n emitResource('housingvista.shortlist.property_added', propertyId);\n notify.success('Saved to shortlist');\n }\n } catch (err) {\n notify.error('Could not update shortlist', (err as Error).message);\n }\n };\n\n // Category, price range, and bedrooms are refined on the client (the subgraph\n // filter input does not model them).\n const filteredProperties = useMemo(() => {\n return properties.filter((property) => {\n const matchesCategory = selectedCategory === 'all' || property.category === selectedCategory;\n const matchesPrice = property.price.amount >= priceRange.min && property.price.amount <= priceRange.max;\n const matchesBedrooms = (property.specifications.bedrooms ?? 0) >= minBedrooms;\n return matchesCategory && matchesPrice && matchesBedrooms;\n });\n }, [properties, selectedCategory, priceRange, minBedrooms]);\n\n const hasNextPage = properties.length >= pageSize;\n\n const hasActiveFilters =\n searchQuery ||\n selectedType !== 'all' ||\n selectedStatus !== 'all' ||\n selectedCategory !== 'all' ||\n selectedPriceRange !== 'all' ||\n selectedBedrooms !== 'all';\n\n const clearFilters = () => {\n setSearchQuery('');\n setSelectedType('all');\n setSelectedStatus('all');\n setSelectedCategory('all');\n setSelectedPriceRange('all');\n setSelectedBedrooms('all');\n };\n\n return (\n <PageLayout\n title={tr('housingvista.properties.title', 'Properties')}\n description={tr(\n 'housingvista.properties.description',\n 'Discover your perfect property from our comprehensive listings'\n )}\n purpose={tr(\n 'housingvista.properties.purpose',\n 'Browse, search, and filter every property in your portfolio or on the market. Use the filters to narrow by type, status, price, and bedrooms, then open any listing to see full details, schedule viewings, or start a transaction.'\n )}\n actions={\n <button\n onClick={() => {\n emit('housingvista.property.create_clicked');\n navigate('new');\n }}\n 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 >\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.properties.actions.addProperty', 'Add Property')}\n </button>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.properties.stats.totalProperties', 'Total Properties')}\n value={dashboardStats.totalProperties}\n icon={<Building className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.properties.stats.portfolioValue', 'Portfolio Value')}\n value={dashboardStats.totalValue}\n prefix=\"$\"\n />\n <StatCard\n label={tr('housingvista.properties.stats.occupancyRate', 'Occupancy Rate')}\n value={dashboardStats.occupancyRate}\n unit=\"%\"\n />\n <StatCard\n label={tr('housingvista.properties.stats.monthlyRevenue', 'Monthly Revenue')}\n value={dashboardStats.monthlyRevenue}\n prefix=\"$\"\n />\n </div>\n </EmphasisPanel>\n\n {/* Search + View Toggle */}\n <FilterBar\n searchValue={searchQuery}\n onSearchChange={setSearchQuery}\n searchPlaceholder={tr(\n 'housingvista.properties.search.placeholder',\n 'Search properties by name, city, or neighborhood...'\n )}\n filters={\n <button\n onClick={() => setShowFilters((prev) => !prev)}\n className={cn(\n 'inline-flex items-center gap-2 rounded-md border border-border-subtle px-3 py-2 text-sm font-medium transition-colors',\n showFilters ? 'bg-foreground text-background' : 'text-text-primary hover:bg-bg-sunken'\n )}\n >\n <SlidersHorizontal className=\"h-4 w-4\" />\n {tr('housingvista.properties.filters.toggle', 'Filters')}\n {hasActiveFilters && (\n <span className=\"flex h-5 w-5 items-center justify-center rounded-full bg-action-primary-bg text-[10px] font-bold text-action-primary-text\">\n !\n </span>\n )}\n </button>\n }\n actions={\n <div className=\"flex items-center gap-1\">\n <button\n onClick={() => setViewMode('grid')}\n className={cn(\n 'rounded-md p-2 transition-colors',\n viewMode === 'grid'\n ? 'bg-foreground text-background'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-sunken'\n )}\n >\n <Grid className=\"h-4 w-4\" />\n </button>\n <button\n onClick={() => setViewMode('list')}\n className={cn(\n 'rounded-md p-2 transition-colors',\n viewMode === 'list'\n ? 'bg-foreground text-background'\n : 'text-text-secondary hover:text-text-primary hover:bg-bg-sunken'\n )}\n >\n <List className=\"h-4 w-4\" />\n </button>\n </div>\n }\n />\n\n {/* Filter Dropdowns */}\n {showFilters && (\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface p-4\">\n <div className=\"flex items-center justify-between mb-4\">\n <h3 className=\"text-sm font-medium text-text-primary\">\n {tr('housingvista.properties.filters.title', 'Filters')}\n </h3>\n {hasActiveFilters && (\n <button\n onClick={clearFilters}\n className=\"inline-flex items-center gap-1 text-xs text-text-secondary hover:text-text-primary\"\n >\n <X className=\"h-3 w-3\" />\n {tr('housingvista.properties.filters.clearAll', 'Clear All')}\n </button>\n )}\n </div>\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3 lg:grid-cols-5\">\n {/* Type */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.propertyType', 'Property Type')}\n </label>\n <select\n value={selectedType}\n onChange={(e) => setSelectedType(e.target.value as PropertyType | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyTypes.map((t) => (\n <option key={t.value} value={t.value}>\n {t.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Status */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.status', 'Status')}\n </label>\n <select\n value={selectedStatus}\n onChange={(e) => setSelectedStatus(e.target.value as PropertyStatus | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyStatuses.map((s) => (\n <option key={s.value} value={s.value}>\n {s.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Category */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.category', 'Category')}\n </label>\n <select\n value={selectedCategory}\n onChange={(e) => setSelectedCategory(e.target.value as PropertyCategory | 'all')}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {propertyCategories.map((c) => (\n <option key={c.value} value={c.value}>\n {c.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Price Range */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.priceRange', 'Price Range')}\n </label>\n <select\n value={selectedPriceRange}\n onChange={(e) => setSelectedPriceRange(e.target.value)}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {priceRanges.map((r) => (\n <option key={r.value} value={r.value}>\n {r.label}\n </option>\n ))}\n </select>\n </div>\n\n {/* Bedrooms */}\n <div>\n <label className=\"mb-1.5 block text-xs font-medium text-text-secondary\">\n {tr('housingvista.properties.filters.labels.bedrooms', 'Bedrooms')}\n </label>\n <select\n value={selectedBedrooms}\n onChange={(e) => setSelectedBedrooms(e.target.value)}\n className=\"h-9 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n >\n {bedroomOptions.map((b) => (\n <option key={b.value} value={b.value}>\n {b.label}\n </option>\n ))}\n </select>\n </div>\n </div>\n </div>\n )}\n\n {/* Results Count */}\n <div className=\"flex items-center justify-between\">\n <p className=\"text-sm text-text-secondary\">\n {tr('housingvista.properties.results.showing', 'Showing')} {filteredProperties.length}{' '}\n {tr('housingvista.properties.results.properties', 'properties')}\n {page > 1 ? ` · page ${page}` : ''}\n </p>\n {hasActiveFilters && (\n <button onClick={clearFilters} className=\"text-sm text-text-secondary hover:text-text-primary\">\n {tr('housingvista.properties.results.clearFilters', 'Clear Filters')}\n </button>\n )}\n </div>\n\n {/* Property Grid / List */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : filteredProperties.length > 0 ? (\n <>\n <div\n className={cn(viewMode === 'grid' ? 'grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3' : 'space-y-4')}\n >\n {filteredProperties.map((property) => (\n <PropertyCard\n key={property.id}\n id={property.id}\n title={property.title}\n price={property.price.amount}\n priceType={property.price.type === 'rent' ? 'rent' : 'sale'}\n pricePeriod={property.price.period}\n currency={property.price.currency}\n location={[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n bedrooms={property.specifications.bedrooms}\n bathrooms={property.specifications.bathrooms}\n area={property.specifications.totalArea}\n imageUrl={property.images[0]?.url}\n status={property.status.replace('_', ' ')}\n type={property.category}\n onClick={() => navigate(property.id)}\n isShortlisted={shortlistedIds.has(property.id)}\n onToggleShortlist={() => toggleShortlist(property.id)}\n />\n ))}\n </div>\n\n {/* Pagination (server-side): working prev/next + page-size, no silent truncation */}\n <Pagination\n page={page}\n pageSize={pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={page > 1}\n loading={loading}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<Building className=\"h-12 w-12\" />}\n title={tr('housingvista.properties.empty.title', 'No properties found')}\n description={tr(\n 'housingvista.properties.empty.description',\n 'Try adjusting your search criteria or filters to find more properties.'\n )}\n action={\n <button\n onClick={clearFilters}\n className=\"rounded-md bg-foreground px-4 py-2 text-sm font-medium text-background transition-colors hover:bg-foreground/90\"\n >\n {tr('housingvista.properties.empty.clearAllFilters', 'Clear All Filters')}\n </button>\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HousingVista Property Detail Page
|
|
3
|
+
* Full property detail view backed by the single-item `housingvistaProperty(id)`
|
|
4
|
+
* query, with the core buyer journey wired to real mutations: shortlist, book a
|
|
5
|
+
* viewing, submit an offer, plus owner-side edit and delete.
|
|
6
|
+
* @module housingvista
|
|
7
|
+
*/
|
|
8
|
+
export declare const PropertyDetailPage: () => import("react").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=PropertyDetailPage.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"PropertyDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/properties/PropertyDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2HH,eAAO,MAAM,kBAAkB,mCA+vC9B,CAAC"}
|