@burdenoff/microfe-housingvista 2026.624.2 → 2026.625.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/housingvista/components/ChartCard.js +11 -9
- package/dist/housingvista/components/ChartCard.js.map +1 -1
- package/dist/housingvista/components/DataTable.js +63 -60
- package/dist/housingvista/components/DataTable.js.map +1 -1
- package/dist/housingvista/components/EmptyState.js +16 -9
- package/dist/housingvista/components/EmptyState.js.map +1 -1
- package/dist/housingvista/components/PageLayout.js +21 -14
- package/dist/housingvista/components/PageLayout.js.map +1 -1
- package/dist/housingvista/components/PropertyCard.js +2 -2
- package/dist/housingvista/components/PropertyCard.js.map +1 -1
- package/dist/housingvista/components/StatCard.js +20 -17
- package/dist/housingvista/components/StatCard.js.map +1 -1
- package/dist/housingvista/components/StatusBadge.js +1 -1
- package/dist/housingvista/components/StatusBadge.js.map +1 -1
- package/dist/housingvista/pages/HomePage.js +101 -58
- package/dist/housingvista/pages/HomePage.js.map +1 -1
- package/dist/housingvista/pages/amc/AMCManagementPage.js +59 -48
- package/dist/housingvista/pages/amc/AMCManagementPage.js.map +1 -1
- package/dist/housingvista/pages/analytics/AnalyticsPage.js +113 -90
- package/dist/housingvista/pages/analytics/AnalyticsPage.js.map +1 -1
- package/dist/housingvista/pages/assets/AssetManagementPage.js +66 -60
- package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
- package/dist/housingvista/pages/chat/ChatPage.js +60 -58
- package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
- package/dist/housingvista/pages/finance/HomeLoansPage.js +23 -20
- package/dist/housingvista/pages/finance/HomeLoansPage.js.map +1 -1
- package/dist/housingvista/pages/investments/InvestmentDetailPage.js +114 -81
- package/dist/housingvista/pages/investments/InvestmentDetailPage.js.map +1 -1
- package/dist/housingvista/pages/investments/InvestmentsPage.js +65 -59
- package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
- package/dist/housingvista/pages/legal/LegalPage.js +17 -14
- package/dist/housingvista/pages/legal/LegalPage.js.map +1 -1
- package/dist/housingvista/pages/market/AreaInsightsPage.js +13 -10
- package/dist/housingvista/pages/market/AreaInsightsPage.js.map +1 -1
- package/dist/housingvista/pages/market/MarketAnalyticsPage.js +155 -123
- package/dist/housingvista/pages/market/MarketAnalyticsPage.js.map +1 -1
- package/dist/housingvista/pages/marketplace/MarketplacePage.js +15 -12
- package/dist/housingvista/pages/marketplace/MarketplacePage.js.map +1 -1
- package/dist/housingvista/pages/notifications/NotificationsPage.js +24 -21
- package/dist/housingvista/pages/notifications/NotificationsPage.js.map +1 -1
- package/dist/housingvista/pages/properties/AddPropertyPage.js +73 -71
- package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertiesPage.js +141 -135
- package/dist/housingvista/pages/properties/PropertiesPage.js.map +1 -1
- package/dist/housingvista/pages/properties/PropertyDetailPage.js +192 -154
- package/dist/housingvista/pages/properties/PropertyDetailPage.js.map +1 -1
- package/dist/housingvista/pages/rental/RentalManagementPage.js +185 -160
- package/dist/housingvista/pages/rental/RentalManagementPage.js.map +1 -1
- package/dist/housingvista/pages/settings/ProfilePage.js +51 -49
- package/dist/housingvista/pages/settings/ProfilePage.js.map +1 -1
- package/dist/housingvista/pages/settings/SettingsPage.js +56 -54
- package/dist/housingvista/pages/settings/SettingsPage.js.map +1 -1
- package/dist/housingvista/pages/transactions/TransactionDetailPage.js +183 -142
- package/dist/housingvista/pages/transactions/TransactionDetailPage.js.map +1 -1
- package/dist/housingvista/pages/transactions/TransactionsPage.js +90 -84
- package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
- package/dist/housingvista/pages/verification/VerificationPage.js +49 -42
- package/dist/housingvista/pages/verification/VerificationPage.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/housingvista/components/StatCard.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { cn } from '../utils/helpers';\nimport { formatNumber, formatCurrency } from '../utils/helpers';\n\ninterface StatCardProps {\n label: string;\n value: number | string;\n previousValue?: number;\n unit?: string;\n prefix?: string;\n icon?: ReactNode;\n trend?: 'up' | 'down' | 'stable';\n change?: number;\n className?: string;\n}\n\nexport const StatCard: FC<StatCardProps> = ({\n label,\n value,\n previousValue,\n unit,\n prefix,\n icon,\n trend,\n change,\n className,\n}) => {\n const numericValue = typeof value === 'number' ? value : 0;\n const computedChange =\n change ?? (previousValue ? Math.round(((numericValue - previousValue) / previousValue) * 100) : 0);\n const computedTrend = trend ?? (computedChange > 0 ? 'up' : computedChange < 0 ? 'down' : 'stable');\n\n const displayValue =\n typeof value === 'string'\n ? value\n : prefix === '$'\n ? formatCurrency(value)\n : `${formatNumber(value)}${unit ? ` ${unit}` : ''}`;\n\n return (\n <
|
|
1
|
+
{"version":3,"file":"StatCard.js","names":[],"sources":["../../../src/housingvista/components/StatCard.tsx"],"sourcesContent":["import type { FC, ReactNode } from 'react';\nimport { TrendingUp, TrendingDown, Minus } from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport { cn } from '../utils/helpers';\nimport { formatNumber, formatCurrency } from '../utils/helpers';\n\ninterface StatCardProps {\n label: string;\n value: number | string;\n previousValue?: number;\n unit?: string;\n prefix?: string;\n icon?: ReactNode;\n trend?: 'up' | 'down' | 'stable';\n change?: number;\n className?: string;\n /** Render the featured hero metric with a glass treatment + accent glow. */\n featured?: boolean;\n}\n\nexport const StatCard: FC<StatCardProps> = ({\n label,\n value,\n previousValue,\n unit,\n prefix,\n icon,\n trend,\n change,\n className,\n featured = false,\n}) => {\n const numericValue = typeof value === 'number' ? value : 0;\n const computedChange =\n change ?? (previousValue ? Math.round(((numericValue - previousValue) / previousValue) * 100) : 0);\n const computedTrend = trend ?? (computedChange > 0 ? 'up' : computedChange < 0 ? 'down' : 'stable');\n\n const displayValue =\n typeof value === 'string'\n ? value\n : prefix === '$'\n ? formatCurrency(value)\n : `${formatNumber(value)}${unit ? ` ${unit}` : ''}`;\n\n return (\n <GlassCard\n treatment={featured ? 'glass' : 'metric'}\n glow={featured}\n className={cn('border-border-seam p-4', className)}\n >\n <div className=\"flex items-center justify-between\">\n <span className=\"text-sm font-medium text-text-secondary\">{label}</span>\n {icon && <span className=\"text-text-secondary\">{icon}</span>}\n </div>\n <div className=\"mt-2 flex items-baseline gap-2\">\n <span className=\"text-2xl font-bold tabular-nums text-text-primary\">{displayValue}</span>\n </div>\n {computedChange !== 0 && (\n <div className=\"mt-2 flex items-center gap-1 text-xs\">\n {computedTrend === 'up' && <TrendingUp className=\"h-3 w-3 text-emerald-600 dark:text-emerald-400\" />}\n {computedTrend === 'down' && <TrendingDown className=\"h-3 w-3 text-red-600 dark:text-red-400\" />}\n {computedTrend === 'stable' && <Minus className=\"h-3 w-3 text-text-secondary\" />}\n <span\n className={cn(\n 'font-medium tabular-nums',\n computedTrend === 'up' && 'text-emerald-600 dark:text-emerald-400',\n computedTrend === 'down' && 'text-red-600 dark:text-red-400',\n computedTrend === 'stable' && 'text-text-secondary'\n )}\n >\n {computedChange > 0 ? '+' : ''}\n {computedChange}%\n </span>\n <span className=\"text-text-secondary\">vs last period</span>\n </div>\n )}\n </GlassCard>\n );\n};\n"],"mappings":";;;;;AAoBA,IAAa,KAA+B,EAC1C,UACA,UACA,kBACA,SACA,WACA,SACA,UACA,WACA,cACA,cAAW,SACP;CAEJ,IAAM,IACJ,MAAW,IAAgB,KAAK,QAFb,OAAO,KAAU,WAAW,IAAQ,KAEA,KAAiB,IAAiB,IAAI,GAAG,IAC5F,IAAgB,MAAU,IAAiB,IAAI,OAAO,IAAiB,IAAI,SAAS,WAEpF,IACJ,OAAO,KAAU,WACb,IACA,MAAW,MACT,EAAe,EAAM,GACrB,GAAG,EAAa,EAAM,GAAG,IAAO,IAAI,MAAS;AAErD,QACE,kBAAC,GAAD;EACE,WAAW,IAAW,UAAU;EAChC,MAAM;EACN,WAAW,EAAG,0BAA0B,EAAU;YAHpD;GAKE,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,QAAD;KAAM,WAAU;eAA2C;KAAa,CAAA,EACvE,KAAQ,kBAAC,QAAD;KAAM,WAAU;eAAuB;KAAY,CAAA,CACxD;;GACN,kBAAC,OAAD;IAAK,WAAU;cACb,kBAAC,QAAD;KAAM,WAAU;eAAqD;KAAoB,CAAA;IACrF,CAAA;GACL,MAAmB,KAClB,kBAAC,OAAD;IAAK,WAAU;cAAf;KACG,MAAkB,QAAQ,kBAAC,GAAD,EAAY,WAAU,kDAAmD,CAAA;KACnG,MAAkB,UAAU,kBAAC,GAAD,EAAc,WAAU,0CAA2C,CAAA;KAC/F,MAAkB,YAAY,kBAAC,GAAD,EAAO,WAAU,+BAAgC,CAAA;KAChF,kBAAC,QAAD;MACE,WAAW,EACT,4BACA,MAAkB,QAAQ,0CAC1B,MAAkB,UAAU,kCAC5B,MAAkB,YAAY,sBAC/B;gBANH;OAQG,IAAiB,IAAI,MAAM;OAC3B;OAAe;OACX;;KACP,kBAAC,QAAD;MAAM,WAAU;gBAAsB;MAAqB,CAAA;KACvD;;GAEE"}
|
|
@@ -17,7 +17,7 @@ var r = {
|
|
|
17
17
|
muted: "bg-muted-foreground"
|
|
18
18
|
}, a = ({ label: a, variant: o = "default", dot: s = !1, className: c }) => /* @__PURE__ */ n("span", {
|
|
19
19
|
className: e("inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium", r[o], c),
|
|
20
|
-
children: [s && /* @__PURE__ */ t("span", { className: e("h-1.5 w-1.5 rounded-full", i[o]) }), a]
|
|
20
|
+
children: [s && /* @__PURE__ */ t("span", { className: e("h-1.5 w-1.5 rounded-full", i[o], o === "success" && "motion-safe:animate-vc-glow-pulse") }), a]
|
|
21
21
|
});
|
|
22
22
|
//#endregion
|
|
23
23
|
export { a as StatusBadge };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/housingvista/components/StatusBadge.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { cn } from '../utils/helpers';\n\ntype BadgeVariant = 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted';\n\ninterface StatusBadgeProps {\n label: string;\n variant?: BadgeVariant;\n dot?: boolean;\n className?: string;\n}\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400',\n warning: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400',\n error: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',\n info: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',\n default: 'bg-action-primary-bg/10 text-primary',\n muted: 'bg-bg-sunken text-text-secondary',\n};\n\nconst dotStyles: Record<BadgeVariant, string> = {\n success: 'bg-emerald-500',\n warning: 'bg-amber-500',\n error: 'bg-red-500',\n info: 'bg-blue-500',\n default: 'bg-action-primary-bg',\n muted: 'bg-muted-foreground',\n};\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({ label, variant = 'default', dot = false, className }) => {\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {dot && <span
|
|
1
|
+
{"version":3,"file":"StatusBadge.js","names":[],"sources":["../../../src/housingvista/components/StatusBadge.tsx"],"sourcesContent":["import type { FC } from 'react';\nimport { cn } from '../utils/helpers';\n\ntype BadgeVariant = 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted';\n\ninterface StatusBadgeProps {\n label: string;\n variant?: BadgeVariant;\n dot?: boolean;\n className?: string;\n}\n\nconst variantStyles: Record<BadgeVariant, string> = {\n success: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/30 dark:text-emerald-400',\n warning: 'bg-amber-100 text-amber-800 dark:bg-amber-900/30 dark:text-amber-400',\n error: 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-400',\n info: 'bg-blue-100 text-blue-800 dark:bg-blue-900/30 dark:text-blue-400',\n default: 'bg-action-primary-bg/10 text-primary',\n muted: 'bg-bg-sunken text-text-secondary',\n};\n\nconst dotStyles: Record<BadgeVariant, string> = {\n success: 'bg-emerald-500',\n warning: 'bg-amber-500',\n error: 'bg-red-500',\n info: 'bg-blue-500',\n default: 'bg-action-primary-bg',\n muted: 'bg-muted-foreground',\n};\n\nexport const StatusBadge: FC<StatusBadgeProps> = ({ label, variant = 'default', dot = false, className }) => {\n return (\n <span\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-full px-2.5 py-0.5 text-xs font-medium',\n variantStyles[variant],\n className\n )}\n >\n {dot && (\n <span\n className={cn(\n 'h-1.5 w-1.5 rounded-full',\n dotStyles[variant],\n variant === 'success' && 'motion-safe:animate-vc-glow-pulse'\n )}\n />\n )}\n {label}\n </span>\n );\n};\n"],"mappings":";;;AAYA,IAAM,IAA8C;CAClD,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACR,EAEK,IAA0C;CAC9C,SAAS;CACT,SAAS;CACT,OAAO;CACP,MAAM;CACN,SAAS;CACT,OAAO;CACR,EAEY,KAAqC,EAAE,UAAO,aAAU,WAAW,SAAM,IAAO,mBAEzF,kBAAC,QAAD;CACE,WAAW,EACT,mFACA,EAAc,IACd,EACD;WALH,CAOG,KACC,kBAAC,QAAD,EACE,WAAW,EACT,4BACA,EAAU,IACV,MAAY,aAAa,oCAC1B,EACD,CAAA,EAEH,EACI"}
|
|
@@ -8,8 +8,9 @@ import { ArrowRight as l, BarChart3 as u, Building as d, DollarSign as f, Eye as
|
|
|
8
8
|
import { useNavigate as v } from "react-router-dom";
|
|
9
9
|
import { jsx as y, jsxs as b } from "react/jsx-runtime";
|
|
10
10
|
import { useI18n as x } from "@burdenoff/fe-libs/shared/providers/shell/I18nProvider";
|
|
11
|
+
import { AuroraBackground as S, Button as C, EmphasisPanel as w, GlassCard as T, GradientText as E, IllustratedEmptyState as D, NextSteps as O, PagePurpose as k } from "@burdenoff/fe-libs/ui";
|
|
11
12
|
//#region src/housingvista/pages/HomePage.tsx
|
|
12
|
-
var
|
|
13
|
+
var A = {
|
|
13
14
|
property_listed: h,
|
|
14
15
|
transaction_update: m,
|
|
15
16
|
payment_received: f,
|
|
@@ -18,7 +19,7 @@ var S = {
|
|
|
18
19
|
document_uploaded: m,
|
|
19
20
|
offer_received: _,
|
|
20
21
|
lease_signed: m
|
|
21
|
-
},
|
|
22
|
+
}, j = {
|
|
22
23
|
property_listed: "text-purple-600 dark:text-purple-400",
|
|
23
24
|
transaction_update: "text-blue-600 dark:text-blue-400",
|
|
24
25
|
payment_received: "text-emerald-600 dark:text-emerald-400",
|
|
@@ -27,83 +28,111 @@ var S = {
|
|
|
27
28
|
document_uploaded: "text-indigo-600 dark:text-indigo-400",
|
|
28
29
|
offer_received: "text-emerald-600 dark:text-emerald-400",
|
|
29
30
|
lease_signed: "text-teal-600 dark:text-teal-400"
|
|
30
|
-
},
|
|
31
|
-
let h = v(), { t:
|
|
32
|
-
let n =
|
|
31
|
+
}, M = () => {
|
|
32
|
+
let h = v(), { t: M } = x(), { data: N } = a(), { data: P } = s(), { data: F } = o(), I = (e, t) => {
|
|
33
|
+
let n = M(e);
|
|
33
34
|
return n === e ? t : n;
|
|
34
|
-
},
|
|
35
|
+
}, L = [
|
|
35
36
|
{
|
|
36
|
-
title:
|
|
37
|
-
description:
|
|
37
|
+
title: I("housingvista.home.quickActions.addProperty.title", "Add Property"),
|
|
38
|
+
description: I("housingvista.home.quickActions.addProperty.description", "List a new property"),
|
|
38
39
|
icon: g,
|
|
39
40
|
path: "properties/new"
|
|
40
41
|
},
|
|
41
42
|
{
|
|
42
|
-
title:
|
|
43
|
-
description:
|
|
43
|
+
title: I("housingvista.home.quickActions.viewAnalytics.title", "View Analytics"),
|
|
44
|
+
description: I("housingvista.home.quickActions.viewAnalytics.description", "Check performance metrics"),
|
|
44
45
|
icon: u,
|
|
45
46
|
path: "analytics"
|
|
46
47
|
},
|
|
47
48
|
{
|
|
48
|
-
title:
|
|
49
|
-
description:
|
|
49
|
+
title: I("housingvista.home.quickActions.manageTransactions.title", "Manage Transactions"),
|
|
50
|
+
description: I("housingvista.home.quickActions.manageTransactions.description", "Handle ongoing deals"),
|
|
50
51
|
icon: m,
|
|
51
52
|
path: "transactions"
|
|
52
53
|
},
|
|
53
54
|
{
|
|
54
|
-
title:
|
|
55
|
-
description:
|
|
55
|
+
title: I("housingvista.home.quickActions.browseProperties.title", "Browse Properties"),
|
|
56
|
+
description: I("housingvista.home.quickActions.browseProperties.description", "Explore listings"),
|
|
56
57
|
icon: d,
|
|
57
58
|
path: "properties"
|
|
58
59
|
}
|
|
59
|
-
],
|
|
60
|
+
], R = c(() => F.slice(0, 6), [F]);
|
|
60
61
|
return /* @__PURE__ */ b("div", {
|
|
61
62
|
className: "space-y-6 p-6",
|
|
62
63
|
children: [
|
|
63
64
|
/* @__PURE__ */ b("div", {
|
|
64
|
-
className: "
|
|
65
|
-
children: [/* @__PURE__ */
|
|
66
|
-
className: "
|
|
67
|
-
children:
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
65
|
+
className: "relative overflow-hidden rounded-card border border-border-seam bg-gloss-card p-6 shadow-pop",
|
|
66
|
+
children: [/* @__PURE__ */ y(S, { intensity: "subtle" }), /* @__PURE__ */ b("div", {
|
|
67
|
+
className: "relative flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between",
|
|
68
|
+
children: [/* @__PURE__ */ b("div", { children: [/* @__PURE__ */ y("h1", {
|
|
69
|
+
className: "text-3xl font-bold text-text-primary",
|
|
70
|
+
children: /* @__PURE__ */ y(E, { children: I("housingvista.home.header.title", "Welcome back!") })
|
|
71
|
+
}), /* @__PURE__ */ y("p", {
|
|
72
|
+
className: "mt-1 text-text-secondary",
|
|
73
|
+
children: I("housingvista.home.header.description", "Here's what's happening with your real estate portfolio today.")
|
|
74
|
+
})] }), /* @__PURE__ */ b(C, {
|
|
74
75
|
onClick: () => h("properties/new"),
|
|
75
|
-
className: "
|
|
76
|
-
children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }),
|
|
77
|
-
})
|
|
76
|
+
className: "gap-2 self-start lg:self-auto",
|
|
77
|
+
children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }), I("housingvista.home.header.quickAdd", "Quick Add")]
|
|
78
|
+
})]
|
|
78
79
|
})]
|
|
79
80
|
}),
|
|
81
|
+
/* @__PURE__ */ y(k, {
|
|
82
|
+
className: "max-w-3xl",
|
|
83
|
+
children: I("housingvista.home.purpose", "Your real-estate command center. See your portfolio at a glance, jump to the things you do most, and pick up where you left off — from listing a property to tracking deals and analytics.")
|
|
84
|
+
}),
|
|
85
|
+
/* @__PURE__ */ y(O, {
|
|
86
|
+
storageKey: "housingvista-home",
|
|
87
|
+
steps: [
|
|
88
|
+
{
|
|
89
|
+
id: "add-property",
|
|
90
|
+
label: I("housingvista.home.nextSteps.addProperty", "List your first property"),
|
|
91
|
+
description: I("housingvista.home.nextSteps.addPropertyDesc", "Create a market-ready listing in a few guided steps."),
|
|
92
|
+
onClick: () => h("properties/new")
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
id: "browse",
|
|
96
|
+
label: I("housingvista.home.nextSteps.browse", "Browse properties"),
|
|
97
|
+
description: I("housingvista.home.nextSteps.browseDesc", "Explore listings and open one for full details."),
|
|
98
|
+
onClick: () => h("properties")
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: "analytics",
|
|
102
|
+
label: I("housingvista.home.nextSteps.analytics", "Review your analytics"),
|
|
103
|
+
description: I("housingvista.home.nextSteps.analyticsDesc", "Check portfolio performance and market insights."),
|
|
104
|
+
onClick: () => h("analytics")
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
}),
|
|
80
108
|
/* @__PURE__ */ b("div", {
|
|
81
109
|
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
82
110
|
children: [
|
|
83
111
|
/* @__PURE__ */ y(r, {
|
|
84
|
-
label:
|
|
85
|
-
value:
|
|
112
|
+
label: I("housingvista.home.stats.totalProperties", "Total Properties"),
|
|
113
|
+
value: N.totalProperties,
|
|
86
114
|
icon: /* @__PURE__ */ y(d, { className: "h-5 w-5" }),
|
|
87
115
|
trend: "up",
|
|
88
|
-
change: 12
|
|
116
|
+
change: 12,
|
|
117
|
+
featured: !0
|
|
89
118
|
}),
|
|
90
119
|
/* @__PURE__ */ y(r, {
|
|
91
|
-
label:
|
|
92
|
-
value:
|
|
120
|
+
label: I("housingvista.home.stats.activeListings", "Active Listings"),
|
|
121
|
+
value: N.activeTransactions,
|
|
93
122
|
icon: /* @__PURE__ */ y(_, { className: "h-5 w-5" }),
|
|
94
123
|
trend: "up",
|
|
95
124
|
change: 8
|
|
96
125
|
}),
|
|
97
126
|
/* @__PURE__ */ y(r, {
|
|
98
|
-
label:
|
|
127
|
+
label: I("housingvista.home.stats.totalViews", "Total Views"),
|
|
99
128
|
value: t(12540),
|
|
100
129
|
icon: /* @__PURE__ */ y(p, { className: "h-5 w-5" }),
|
|
101
130
|
trend: "down",
|
|
102
131
|
change: -2
|
|
103
132
|
}),
|
|
104
133
|
/* @__PURE__ */ y(r, {
|
|
105
|
-
label:
|
|
106
|
-
value:
|
|
134
|
+
label: I("housingvista.home.stats.monthlyRevenue", "Monthly Revenue"),
|
|
135
|
+
value: N.monthlyRevenue,
|
|
107
136
|
prefix: "$",
|
|
108
137
|
icon: /* @__PURE__ */ y(f, { className: "h-5 w-5" }),
|
|
109
138
|
trend: "up",
|
|
@@ -115,21 +144,22 @@ var S = {
|
|
|
115
144
|
className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
|
|
116
145
|
children: [/* @__PURE__ */ y("div", {
|
|
117
146
|
className: "lg:col-span-1",
|
|
118
|
-
children: /* @__PURE__ */ b(
|
|
119
|
-
|
|
147
|
+
children: /* @__PURE__ */ b(T, {
|
|
148
|
+
treatment: "plain",
|
|
149
|
+
className: "border-border-seam",
|
|
120
150
|
children: [/* @__PURE__ */ y("div", {
|
|
121
|
-
className: "border-b border-border-
|
|
151
|
+
className: "border-b border-border-seam px-5 py-4",
|
|
122
152
|
children: /* @__PURE__ */ y("h2", {
|
|
123
153
|
className: "text-base font-semibold text-text-primary",
|
|
124
|
-
children:
|
|
154
|
+
children: I("housingvista.home.quickActions.title", "Quick Actions")
|
|
125
155
|
})
|
|
126
156
|
}), /* @__PURE__ */ y("div", {
|
|
127
157
|
className: "space-y-2 p-4",
|
|
128
|
-
children:
|
|
158
|
+
children: L.map((e) => {
|
|
129
159
|
let t = e.icon;
|
|
130
160
|
return /* @__PURE__ */ b("button", {
|
|
131
161
|
onClick: () => h(e.path),
|
|
132
|
-
className: "flex w-full items-center gap-3 rounded-lg border border-border-
|
|
162
|
+
className: "flex min-h-[44px] w-full items-center gap-3 rounded-lg border border-border-seam p-3 text-left transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]",
|
|
133
163
|
children: [/* @__PURE__ */ y("div", {
|
|
134
164
|
className: "rounded-lg bg-action-primary-bg/10 p-2",
|
|
135
165
|
children: /* @__PURE__ */ y(t, { className: "h-5 w-5 text-text-primary" })
|
|
@@ -149,21 +179,21 @@ var S = {
|
|
|
149
179
|
})
|
|
150
180
|
}), /* @__PURE__ */ y("div", {
|
|
151
181
|
className: "lg:col-span-2",
|
|
152
|
-
children: /* @__PURE__ */ b(
|
|
153
|
-
className: "
|
|
182
|
+
children: /* @__PURE__ */ b(w, {
|
|
183
|
+
className: "p-0",
|
|
154
184
|
children: [/* @__PURE__ */ y("div", {
|
|
155
|
-
className: "border-b border-border-
|
|
185
|
+
className: "border-b border-border-seam px-5 py-4",
|
|
156
186
|
children: /* @__PURE__ */ y("h2", {
|
|
157
187
|
className: "text-base font-semibold text-text-primary",
|
|
158
|
-
children:
|
|
188
|
+
children: I("housingvista.home.recentActivity.title", "Recent Activity")
|
|
159
189
|
})
|
|
160
190
|
}), /* @__PURE__ */ y("div", {
|
|
161
191
|
className: "space-y-2 p-4",
|
|
162
|
-
children:
|
|
163
|
-
className: "flex items-start gap-4 rounded-lg border border-border-
|
|
192
|
+
children: P.slice(0, 6).map((t) => /* @__PURE__ */ b("div", {
|
|
193
|
+
className: "flex items-start gap-4 rounded-lg border border-border-seam bg-bg-surface/60 p-4 transition-colors hover:bg-bg-sunken/50",
|
|
164
194
|
children: [/* @__PURE__ */ y("div", {
|
|
165
195
|
className: "rounded-lg bg-bg-sunken p-2",
|
|
166
|
-
children: /* @__PURE__ */ y(
|
|
196
|
+
children: /* @__PURE__ */ y(A[t.type] ?? p, { className: e("h-5 w-5", j[t.type] ?? "text-text-secondary") })
|
|
167
197
|
}), /* @__PURE__ */ b("div", {
|
|
168
198
|
className: "flex-1 min-w-0",
|
|
169
199
|
children: [
|
|
@@ -186,21 +216,34 @@ var S = {
|
|
|
186
216
|
})
|
|
187
217
|
})]
|
|
188
218
|
}),
|
|
189
|
-
/* @__PURE__ */ b(
|
|
190
|
-
|
|
219
|
+
/* @__PURE__ */ b(T, {
|
|
220
|
+
treatment: "plain",
|
|
221
|
+
className: "border-border-seam",
|
|
191
222
|
children: [/* @__PURE__ */ b("div", {
|
|
192
|
-
className: "flex items-center justify-between border-b border-border-
|
|
223
|
+
className: "flex items-center justify-between border-b border-border-seam px-5 py-4",
|
|
193
224
|
children: [/* @__PURE__ */ y("h2", {
|
|
194
225
|
className: "text-base font-semibold text-text-primary",
|
|
195
|
-
children:
|
|
226
|
+
children: I("housingvista.home.recentProperties.title", "Recent Properties")
|
|
196
227
|
}), /* @__PURE__ */ b("button", {
|
|
197
228
|
onClick: () => h("properties"),
|
|
198
|
-
className: "inline-flex items-center gap-1 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary",
|
|
199
|
-
children: [
|
|
229
|
+
className: "inline-flex min-h-[44px] items-center gap-1 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] rounded-md px-1",
|
|
230
|
+
children: [I("housingvista.home.recentProperties.viewAll", "View All"), /* @__PURE__ */ y(l, { className: "h-4 w-4" })]
|
|
200
231
|
})]
|
|
201
|
-
}), /* @__PURE__ */ y("div", {
|
|
232
|
+
}), R.length === 0 ? /* @__PURE__ */ y("div", {
|
|
233
|
+
className: "p-4",
|
|
234
|
+
children: /* @__PURE__ */ y(D, {
|
|
235
|
+
illustration: "empty-data",
|
|
236
|
+
title: I("housingvista.home.recentProperties.empty.title", "No properties yet"),
|
|
237
|
+
description: I("housingvista.home.recentProperties.empty.description", "List your first property to see it appear here."),
|
|
238
|
+
action: /* @__PURE__ */ b(C, {
|
|
239
|
+
onClick: () => h("properties/new"),
|
|
240
|
+
className: "gap-2",
|
|
241
|
+
children: [/* @__PURE__ */ y(g, { className: "h-4 w-4" }), I("housingvista.home.header.quickAdd", "Quick Add")]
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
}) : /* @__PURE__ */ y("div", {
|
|
202
245
|
className: "grid grid-cols-1 gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3",
|
|
203
|
-
children:
|
|
246
|
+
children: R.map((e) => /* @__PURE__ */ y(i, {
|
|
204
247
|
id: e.id,
|
|
205
248
|
title: e.title,
|
|
206
249
|
price: e.price.amount,
|
|
@@ -221,6 +264,6 @@ var S = {
|
|
|
221
264
|
});
|
|
222
265
|
};
|
|
223
266
|
//#endregion
|
|
224
|
-
export {
|
|
267
|
+
export { M as HomePage };
|
|
225
268
|
|
|
226
269
|
//# sourceMappingURL=HomePage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/housingvista/pages/HomePage.tsx"],"sourcesContent":["/**\n * HousingVista Dashboard / Home Page\n * Migrated from legacy housingvista-frontend dashboard.tsx\n * @module housingvista\n */\n\nimport { useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport { Building, TrendingUp, Eye, DollarSign, Plus, BarChart3, FileText, Home, ArrowRight } from 'lucide-react';\nimport { StatCard, PropertyCard } from '../components';\nimport { useDashboardStats, useRecentActivities, useProperties } from '../hooks';\nimport { cn, formatNumber, getRelativeTime } from '../utils/helpers';\nimport type { RecentActivity } from '../types';\n\n// ---- Activity icon mapping ----\nconst activityIconMap: Record<RecentActivity['type'], typeof Eye> = {\n property_listed: Home,\n transaction_update: FileText,\n payment_received: DollarSign,\n maintenance_request: Building,\n viewing_scheduled: Eye,\n document_uploaded: FileText,\n offer_received: TrendingUp,\n lease_signed: FileText,\n};\n\nconst activityColorMap: Record<RecentActivity['type'], string> = {\n property_listed: 'text-purple-600 dark:text-purple-400',\n transaction_update: 'text-blue-600 dark:text-blue-400',\n payment_received: 'text-emerald-600 dark:text-emerald-400',\n maintenance_request: 'text-amber-600 dark:text-amber-400',\n viewing_scheduled: 'text-sky-600 dark:text-sky-400',\n document_uploaded: 'text-indigo-600 dark:text-indigo-400',\n offer_received: 'text-emerald-600 dark:text-emerald-400',\n lease_signed: 'text-teal-600 dark:text-teal-400',\n};\n\nexport const HomePage = () => {\n const navigate = useNavigate();\n const { t } = useI18n();\n const { data: stats } = useDashboardStats();\n const { data: activities } = useRecentActivities();\n const { data: properties } = useProperties();\n\n const tr = (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const quickActions = [\n {\n title: tr('housingvista.home.quickActions.addProperty.title', 'Add Property'),\n description: tr('housingvista.home.quickActions.addProperty.description', 'List a new property'),\n icon: Plus,\n path: 'properties/new',\n },\n {\n title: tr('housingvista.home.quickActions.viewAnalytics.title', 'View Analytics'),\n description: tr('housingvista.home.quickActions.viewAnalytics.description', 'Check performance metrics'),\n icon: BarChart3,\n path: 'analytics',\n },\n {\n title: tr('housingvista.home.quickActions.manageTransactions.title', 'Manage Transactions'),\n description: tr('housingvista.home.quickActions.manageTransactions.description', 'Handle ongoing deals'),\n icon: FileText,\n path: 'transactions',\n },\n {\n title: tr('housingvista.home.quickActions.browseProperties.title', 'Browse Properties'),\n description: tr('housingvista.home.quickActions.browseProperties.description', 'Explore listings'),\n icon: Building,\n path: 'properties',\n },\n ];\n\n const recentProperties = useMemo(() => properties.slice(0, 6), [properties]);\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Welcome Header */}\n <div className=\"flex flex-col lg:flex-row lg:items-center lg:justify-between gap-4 rounded-xl border border-border-subtle bg-bg-surface p-6 shadow-sm\">\n <div>\n <h1 className=\"text-3xl font-bold text-text-primary\">\n {tr('housingvista.home.header.title', 'Welcome back!')}\n </h1>\n <p className=\"mt-1 text-text-secondary\">\n {tr(\n 'housingvista.home.header.description',\n \"Here's what's happening with your real estate portfolio today.\"\n )}\n </p>\n </div>\n <div className=\"flex items-center gap-3\">\n <button\n onClick={() => navigate('properties/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.home.header.quickAdd', 'Quick Add')}\n </button>\n </div>\n </div>\n\n {/* Stats Grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.home.stats.totalProperties', 'Total Properties')}\n value={stats.totalProperties}\n icon={<Building className=\"h-5 w-5\" />}\n trend=\"up\"\n change={12}\n />\n <StatCard\n label={tr('housingvista.home.stats.activeListings', 'Active Listings')}\n value={stats.activeTransactions}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n trend=\"up\"\n change={8}\n />\n <StatCard\n label={tr('housingvista.home.stats.totalViews', 'Total Views')}\n value={formatNumber(12540)}\n icon={<Eye className=\"h-5 w-5\" />}\n trend=\"down\"\n change={-2}\n />\n <StatCard\n label={tr('housingvista.home.stats.monthlyRevenue', 'Monthly Revenue')}\n value={stats.monthlyRevenue}\n prefix=\"$\"\n icon={<DollarSign className=\"h-5 w-5\" />}\n trend=\"up\"\n change={15}\n />\n </div>\n\n {/* Quick Actions + Recent Activity */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Quick Actions */}\n <div className=\"lg:col-span-1\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm\">\n <div className=\"border-b border-border-subtle px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.quickActions.title', 'Quick Actions')}\n </h2>\n </div>\n <div className=\"space-y-2 p-4\">\n {quickActions.map((action) => {\n const Icon = action.icon;\n return (\n <button\n key={action.title}\n onClick={() => navigate(action.path)}\n className=\"flex w-full items-center gap-3 rounded-lg border border-border-subtle p-3 text-left transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"rounded-lg bg-action-primary-bg/10 p-2\">\n <Icon className=\"h-5 w-5 text-text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-text-primary\">{action.title}</div>\n <div className=\"text-xs text-text-secondary\">{action.description}</div>\n </div>\n </button>\n );\n })}\n </div>\n </div>\n </div>\n\n {/* Recent Activity */}\n <div className=\"lg:col-span-2\">\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm\">\n <div className=\"border-b border-border-subtle px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.recentActivity.title', 'Recent Activity')}\n </h2>\n </div>\n <div className=\"space-y-2 p-4\">\n {activities.slice(0, 6).map((activity) => {\n const Icon = activityIconMap[activity.type] ?? Eye;\n const colorClass = activityColorMap[activity.type] ?? 'text-text-secondary';\n return (\n <div\n key={activity.id}\n className=\"flex items-start gap-4 rounded-lg border border-border-subtle p-4 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"rounded-lg bg-bg-sunken p-2\">\n <Icon className={cn('h-5 w-5', colorClass)} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">{activity.title}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">{activity.description}</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {getRelativeTime(activity.timestamp)}\n {activity.actorName && ` · ${activity.actorName}`}\n </p>\n </div>\n </div>\n );\n })}\n </div>\n </div>\n </div>\n </div>\n\n {/* Recent Properties */}\n <div className=\"rounded-lg border border-border-subtle bg-bg-surface shadow-sm\">\n <div className=\"flex items-center justify-between border-b border-border-subtle px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.recentProperties.title', 'Recent Properties')}\n </h2>\n <button\n onClick={() => navigate('properties')}\n className=\"inline-flex items-center gap-1 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n {tr('housingvista.home.recentProperties.viewAll', 'View All')}\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n <div className=\"grid grid-cols-1 gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3\">\n {recentProperties.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 location={`${property.location.neighborhood}, ${property.location.city}`}\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(`properties/${property.id}`)}\n />\n ))}\n </div>\n </div>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HomePage.js","names":[],"sources":["../../../src/housingvista/pages/HomePage.tsx"],"sourcesContent":["/**\n * HousingVista Dashboard / Home Page\n * Migrated from legacy housingvista-frontend dashboard.tsx\n * @module housingvista\n */\n\nimport { useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\nimport {\n AuroraBackground,\n GradientText,\n Button,\n GlassCard,\n EmphasisPanel,\n IllustratedEmptyState,\n PagePurpose,\n NextSteps,\n} from '@burdenoff/fe-libs/ui';\nimport { Building, TrendingUp, Eye, DollarSign, Plus, BarChart3, FileText, Home, ArrowRight } from 'lucide-react';\nimport { StatCard, PropertyCard } from '../components';\nimport { useDashboardStats, useRecentActivities, useProperties } from '../hooks';\nimport { cn, formatNumber, getRelativeTime } from '../utils/helpers';\nimport type { RecentActivity } from '../types';\n\n// ---- Activity icon mapping ----\nconst activityIconMap: Record<RecentActivity['type'], typeof Eye> = {\n property_listed: Home,\n transaction_update: FileText,\n payment_received: DollarSign,\n maintenance_request: Building,\n viewing_scheduled: Eye,\n document_uploaded: FileText,\n offer_received: TrendingUp,\n lease_signed: FileText,\n};\n\nconst activityColorMap: Record<RecentActivity['type'], string> = {\n property_listed: 'text-purple-600 dark:text-purple-400',\n transaction_update: 'text-blue-600 dark:text-blue-400',\n payment_received: 'text-emerald-600 dark:text-emerald-400',\n maintenance_request: 'text-amber-600 dark:text-amber-400',\n viewing_scheduled: 'text-sky-600 dark:text-sky-400',\n document_uploaded: 'text-indigo-600 dark:text-indigo-400',\n offer_received: 'text-emerald-600 dark:text-emerald-400',\n lease_signed: 'text-teal-600 dark:text-teal-400',\n};\n\nexport const HomePage = () => {\n const navigate = useNavigate();\n const { t } = useI18n();\n const { data: stats } = useDashboardStats();\n const { data: activities } = useRecentActivities();\n const { data: properties } = useProperties();\n\n const tr = (key: string, fallback: string) => {\n const translated = t(key);\n return translated === key ? fallback : translated;\n };\n\n const quickActions = [\n {\n title: tr('housingvista.home.quickActions.addProperty.title', 'Add Property'),\n description: tr('housingvista.home.quickActions.addProperty.description', 'List a new property'),\n icon: Plus,\n path: 'properties/new',\n },\n {\n title: tr('housingvista.home.quickActions.viewAnalytics.title', 'View Analytics'),\n description: tr('housingvista.home.quickActions.viewAnalytics.description', 'Check performance metrics'),\n icon: BarChart3,\n path: 'analytics',\n },\n {\n title: tr('housingvista.home.quickActions.manageTransactions.title', 'Manage Transactions'),\n description: tr('housingvista.home.quickActions.manageTransactions.description', 'Handle ongoing deals'),\n icon: FileText,\n path: 'transactions',\n },\n {\n title: tr('housingvista.home.quickActions.browseProperties.title', 'Browse Properties'),\n description: tr('housingvista.home.quickActions.browseProperties.description', 'Explore listings'),\n icon: Building,\n path: 'properties',\n },\n ];\n\n const recentProperties = useMemo(() => properties.slice(0, 6), [properties]);\n\n return (\n <div className=\"space-y-6 p-6\">\n {/* Welcome Header — Boff UI 2.0 aurora hero (one per MFE) */}\n <div className=\"relative overflow-hidden rounded-card border border-border-seam bg-gloss-card p-6 shadow-pop\">\n <AuroraBackground intensity=\"subtle\" />\n <div className=\"relative flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between\">\n <div>\n <h1 className=\"text-3xl font-bold text-text-primary\">\n <GradientText>{tr('housingvista.home.header.title', 'Welcome back!')}</GradientText>\n </h1>\n <p className=\"mt-1 text-text-secondary\">\n {tr(\n 'housingvista.home.header.description',\n \"Here's what's happening with your real estate portfolio today.\"\n )}\n </p>\n </div>\n <Button onClick={() => navigate('properties/new')} className=\"gap-2 self-start lg:self-auto\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.home.header.quickAdd', 'Quick Add')}\n </Button>\n </div>\n </div>\n\n <PagePurpose className=\"max-w-3xl\">\n {tr(\n 'housingvista.home.purpose',\n 'Your real-estate command center. See your portfolio at a glance, jump to the things you do most, and pick up where you left off — from listing a property to tracking deals and analytics.'\n )}\n </PagePurpose>\n\n <NextSteps\n storageKey=\"housingvista-home\"\n steps={[\n {\n id: 'add-property',\n label: tr('housingvista.home.nextSteps.addProperty', 'List your first property'),\n description: tr(\n 'housingvista.home.nextSteps.addPropertyDesc',\n 'Create a market-ready listing in a few guided steps.'\n ),\n onClick: () => navigate('properties/new'),\n },\n {\n id: 'browse',\n label: tr('housingvista.home.nextSteps.browse', 'Browse properties'),\n description: tr('housingvista.home.nextSteps.browseDesc', 'Explore listings and open one for full details.'),\n onClick: () => navigate('properties'),\n },\n {\n id: 'analytics',\n label: tr('housingvista.home.nextSteps.analytics', 'Review your analytics'),\n description: tr(\n 'housingvista.home.nextSteps.analyticsDesc',\n 'Check portfolio performance and market insights.'\n ),\n onClick: () => navigate('analytics'),\n },\n ]}\n />\n\n {/* Stats Grid */}\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.home.stats.totalProperties', 'Total Properties')}\n value={stats.totalProperties}\n icon={<Building className=\"h-5 w-5\" />}\n trend=\"up\"\n change={12}\n featured\n />\n <StatCard\n label={tr('housingvista.home.stats.activeListings', 'Active Listings')}\n value={stats.activeTransactions}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n trend=\"up\"\n change={8}\n />\n <StatCard\n label={tr('housingvista.home.stats.totalViews', 'Total Views')}\n value={formatNumber(12540)}\n icon={<Eye className=\"h-5 w-5\" />}\n trend=\"down\"\n change={-2}\n />\n <StatCard\n label={tr('housingvista.home.stats.monthlyRevenue', 'Monthly Revenue')}\n value={stats.monthlyRevenue}\n prefix=\"$\"\n icon={<DollarSign className=\"h-5 w-5\" />}\n trend=\"up\"\n change={15}\n />\n </div>\n\n {/* Quick Actions + Recent Activity */}\n <div className=\"grid grid-cols-1 gap-6 lg:grid-cols-3\">\n {/* Quick Actions */}\n <div className=\"lg:col-span-1\">\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <div className=\"border-b border-border-seam px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.quickActions.title', 'Quick Actions')}\n </h2>\n </div>\n <div className=\"space-y-2 p-4\">\n {quickActions.map((action) => {\n const Icon = action.icon;\n return (\n <button\n key={action.title}\n onClick={() => navigate(action.path)}\n className=\"flex min-h-[44px] w-full items-center gap-3 rounded-lg border border-border-seam p-3 text-left transition-colors hover:bg-bg-sunken/50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)]\"\n >\n <div className=\"rounded-lg bg-action-primary-bg/10 p-2\">\n <Icon className=\"h-5 w-5 text-text-primary\" />\n </div>\n <div className=\"flex-1 min-w-0\">\n <div className=\"text-sm font-medium text-text-primary\">{action.title}</div>\n <div className=\"text-xs text-text-secondary\">{action.description}</div>\n </div>\n </button>\n );\n })}\n </div>\n </GlassCard>\n </div>\n\n {/* Recent Activity — primary insight zone (one EmphasisPanel per page) */}\n <div className=\"lg:col-span-2\">\n <EmphasisPanel className=\"p-0\">\n <div className=\"border-b border-border-seam px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.recentActivity.title', 'Recent Activity')}\n </h2>\n </div>\n <div className=\"space-y-2 p-4\">\n {activities.slice(0, 6).map((activity) => {\n const Icon = activityIconMap[activity.type] ?? Eye;\n const colorClass = activityColorMap[activity.type] ?? 'text-text-secondary';\n return (\n <div\n key={activity.id}\n className=\"flex items-start gap-4 rounded-lg border border-border-seam bg-bg-surface/60 p-4 transition-colors hover:bg-bg-sunken/50\"\n >\n <div className=\"rounded-lg bg-bg-sunken p-2\">\n <Icon className={cn('h-5 w-5', colorClass)} />\n </div>\n <div className=\"flex-1 min-w-0\">\n <p className=\"text-sm font-medium text-text-primary\">{activity.title}</p>\n <p className=\"text-xs text-text-secondary mt-0.5\">{activity.description}</p>\n <p className=\"text-xs text-text-secondary mt-1\">\n {getRelativeTime(activity.timestamp)}\n {activity.actorName && ` · ${activity.actorName}`}\n </p>\n </div>\n </div>\n );\n })}\n </div>\n </EmphasisPanel>\n </div>\n </div>\n\n {/* Recent Properties */}\n <GlassCard treatment=\"plain\" className=\"border-border-seam\">\n <div className=\"flex items-center justify-between border-b border-border-seam px-5 py-4\">\n <h2 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.home.recentProperties.title', 'Recent Properties')}\n </h2>\n <button\n onClick={() => navigate('properties')}\n className=\"inline-flex min-h-[44px] items-center gap-1 text-sm font-medium text-text-secondary transition-colors hover:text-text-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-focus-ring)] rounded-md px-1\"\n >\n {tr('housingvista.home.recentProperties.viewAll', 'View All')}\n <ArrowRight className=\"h-4 w-4\" />\n </button>\n </div>\n {recentProperties.length === 0 ? (\n <div className=\"p-4\">\n <IllustratedEmptyState\n illustration=\"empty-data\"\n title={tr('housingvista.home.recentProperties.empty.title', 'No properties yet')}\n description={tr(\n 'housingvista.home.recentProperties.empty.description',\n 'List your first property to see it appear here.'\n )}\n action={\n <Button onClick={() => navigate('properties/new')} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.home.header.quickAdd', 'Quick Add')}\n </Button>\n }\n />\n </div>\n ) : (\n <div className=\"grid grid-cols-1 gap-4 p-4 sm:grid-cols-2 lg:grid-cols-3\">\n {recentProperties.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 location={`${property.location.neighborhood}, ${property.location.city}`}\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(`properties/${property.id}`)}\n />\n ))}\n </div>\n )}\n </GlassCard>\n </div>\n );\n};\n"],"mappings":"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"}
|
|
@@ -10,8 +10,9 @@ import { useAMCContracts as l } from "../../hooks/index.js";
|
|
|
10
10
|
import { useMemo as u, useState as d } from "react";
|
|
11
11
|
import { AlertTriangle as f, Calendar as p, Clock as m, DollarSign as h, Download as g, Plus as _, RotateCcw as v, Shield as y, Wrench as b } from "lucide-react";
|
|
12
12
|
import { jsx as x, jsxs as S } from "react/jsx-runtime";
|
|
13
|
+
import { EmphasisPanel as C } from "@burdenoff/fe-libs/ui";
|
|
13
14
|
//#region src/housingvista/pages/amc/AMCManagementPage.tsx
|
|
14
|
-
function
|
|
15
|
+
function w(e) {
|
|
15
16
|
switch (e) {
|
|
16
17
|
case "active": return "success";
|
|
17
18
|
case "expiring_soon": return "warning";
|
|
@@ -20,24 +21,25 @@ function C(e) {
|
|
|
20
21
|
default: return "muted";
|
|
21
22
|
}
|
|
22
23
|
}
|
|
23
|
-
function
|
|
24
|
-
let { data:
|
|
25
|
-
if (!
|
|
26
|
-
let e =
|
|
27
|
-
return
|
|
28
|
-
}, [
|
|
29
|
-
activeContracts:
|
|
30
|
-
pendingRenewals:
|
|
31
|
-
totalMonthlySpent:
|
|
32
|
-
upcomingServices:
|
|
24
|
+
function T() {
|
|
25
|
+
let { data: T } = l(), [E, D] = d(""), O = u(() => {
|
|
26
|
+
if (!E) return T;
|
|
27
|
+
let e = E.toLowerCase();
|
|
28
|
+
return T.filter((t) => t.propertyTitle.toLowerCase().includes(e) || t.providerName.toLowerCase().includes(e) || t.packageName.toLowerCase().includes(e));
|
|
29
|
+
}, [T, E]), k = u(() => ({
|
|
30
|
+
activeContracts: T.filter((e) => e.status === "active" || e.status === "expiring_soon").length,
|
|
31
|
+
pendingRenewals: T.filter((e) => e.status === "expiring_soon").length,
|
|
32
|
+
totalMonthlySpent: T.filter((e) => e.status === "active" || e.status === "expiring_soon").reduce((e, t) => e + t.monthlyCost, 0),
|
|
33
|
+
upcomingServices: T.filter((e) => {
|
|
33
34
|
if (!e.nextServiceDate) return !1;
|
|
34
35
|
let t = new Date(e.nextServiceDate), n = /* @__PURE__ */ new Date(), r = (t.getTime() - n.getTime()) / (1e3 * 60 * 60 * 24);
|
|
35
36
|
return r >= 0 && r <= 30;
|
|
36
37
|
}).length
|
|
37
|
-
}), [
|
|
38
|
+
}), [T]), A = u(() => T.filter((e) => e.nextServiceDate && (e.status === "active" || e.status === "expiring_soon")).sort((e, t) => new Date(e.nextServiceDate).getTime() - new Date(t.nextServiceDate).getTime()), [T]);
|
|
38
39
|
return /* @__PURE__ */ S(r, {
|
|
39
40
|
title: "AMC Management",
|
|
40
41
|
description: "Manage Annual Maintenance Contracts and service packages",
|
|
42
|
+
purpose: "Keep your properties maintained without surprises. Track every Annual Maintenance Contract, see what each covers and costs, get ahead of renewals, and know which services are due in the next 30 days so nothing slips.",
|
|
41
43
|
actions: /* @__PURE__ */ S("div", {
|
|
42
44
|
className: "flex items-center gap-2",
|
|
43
45
|
children: [/* @__PURE__ */ S("button", {
|
|
@@ -49,42 +51,50 @@ function w() {
|
|
|
49
51
|
})]
|
|
50
52
|
}),
|
|
51
53
|
children: [
|
|
52
|
-
/* @__PURE__ */
|
|
53
|
-
className: "
|
|
54
|
-
children:
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
54
|
+
/* @__PURE__ */ x(C, {
|
|
55
|
+
className: "p-4",
|
|
56
|
+
children: /* @__PURE__ */ S("div", {
|
|
57
|
+
className: "grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
58
|
+
children: [
|
|
59
|
+
/* @__PURE__ */ x(i, {
|
|
60
|
+
label: "Active Contracts",
|
|
61
|
+
value: k.activeContracts,
|
|
62
|
+
icon: /* @__PURE__ */ x(y, { className: "h-4 w-4" })
|
|
63
|
+
}),
|
|
64
|
+
/* @__PURE__ */ x(i, {
|
|
65
|
+
label: "Pending Renewals",
|
|
66
|
+
value: k.pendingRenewals,
|
|
67
|
+
icon: /* @__PURE__ */ x(v, { className: "h-4 w-4" }),
|
|
68
|
+
trend: k.pendingRenewals > 0 ? "up" : "stable",
|
|
69
|
+
change: k.pendingRenewals > 0 ? k.pendingRenewals : 0
|
|
70
|
+
}),
|
|
71
|
+
/* @__PURE__ */ x(i, {
|
|
72
|
+
label: "Total Monthly Spent",
|
|
73
|
+
value: k.totalMonthlySpent,
|
|
74
|
+
prefix: "$",
|
|
75
|
+
icon: /* @__PURE__ */ x(h, { className: "h-4 w-4" })
|
|
76
|
+
}),
|
|
77
|
+
/* @__PURE__ */ x(i, {
|
|
78
|
+
label: "Upcoming Services",
|
|
79
|
+
value: k.upcomingServices,
|
|
80
|
+
icon: /* @__PURE__ */ x(p, { className: "h-4 w-4" })
|
|
81
|
+
})
|
|
82
|
+
]
|
|
83
|
+
})
|
|
79
84
|
}),
|
|
80
85
|
/* @__PURE__ */ S("div", {
|
|
81
86
|
className: "rounded-lg border border-border-subtle bg-bg-surface p-5 shadow-sm",
|
|
82
87
|
children: [/* @__PURE__ */ x("h3", {
|
|
83
88
|
className: "mb-4 text-lg font-semibold text-text-primary",
|
|
84
89
|
children: "Upcoming Service Schedule"
|
|
85
|
-
}), /* @__PURE__ */ x(
|
|
90
|
+
}), A.length === 0 ? /* @__PURE__ */ x(s, {
|
|
91
|
+
illustration: "empty-generic",
|
|
92
|
+
title: "No services scheduled",
|
|
93
|
+
description: "Once your active contracts have upcoming service dates, they'll be listed here in order of priority.",
|
|
94
|
+
className: "border-0 bg-transparent p-6"
|
|
95
|
+
}) : /* @__PURE__ */ x("div", {
|
|
86
96
|
className: "space-y-3",
|
|
87
|
-
children:
|
|
97
|
+
children: A.map((t) => {
|
|
88
98
|
let r = new Date(t.nextServiceDate), i = /* @__PURE__ */ new Date(), a = Math.ceil((r.getTime() - i.getTime()) / (1e3 * 60 * 60 * 24)), s = a <= 7, c = a < 0;
|
|
89
99
|
return /* @__PURE__ */ S("div", {
|
|
90
100
|
className: "flex flex-col gap-3 rounded-lg bg-bg-sunken/50 p-4 sm:flex-row sm:items-center sm:justify-between",
|
|
@@ -134,7 +144,7 @@ function w() {
|
|
|
134
144
|
})]
|
|
135
145
|
}), /* @__PURE__ */ x(o, {
|
|
136
146
|
label: t.status.replace("_", " "),
|
|
137
|
-
variant:
|
|
147
|
+
variant: w(t.status)
|
|
138
148
|
})]
|
|
139
149
|
})]
|
|
140
150
|
}, t.id);
|
|
@@ -147,13 +157,13 @@ function w() {
|
|
|
147
157
|
children: "All Contracts"
|
|
148
158
|
}),
|
|
149
159
|
/* @__PURE__ */ x(c, {
|
|
150
|
-
searchValue:
|
|
151
|
-
onSearchChange:
|
|
160
|
+
searchValue: E,
|
|
161
|
+
onSearchChange: D,
|
|
152
162
|
searchPlaceholder: "Search contracts, providers, properties..."
|
|
153
163
|
}),
|
|
154
164
|
/* @__PURE__ */ x("div", {
|
|
155
165
|
className: "mt-4",
|
|
156
|
-
children:
|
|
166
|
+
children: O.length > 0 ? /* @__PURE__ */ x(a, {
|
|
157
167
|
columns: [
|
|
158
168
|
{
|
|
159
169
|
key: "packageName",
|
|
@@ -220,15 +230,16 @@ function w() {
|
|
|
220
230
|
header: "Status",
|
|
221
231
|
render: (e) => /* @__PURE__ */ x(o, {
|
|
222
232
|
label: e.status.replace("_", " "),
|
|
223
|
-
variant:
|
|
233
|
+
variant: w(e.status),
|
|
224
234
|
dot: !0
|
|
225
235
|
})
|
|
226
236
|
}
|
|
227
237
|
],
|
|
228
|
-
data:
|
|
238
|
+
data: O,
|
|
229
239
|
keyField: "id",
|
|
230
240
|
pageSize: 10
|
|
231
241
|
}) : /* @__PURE__ */ x(s, {
|
|
242
|
+
illustration: "empty-search",
|
|
232
243
|
icon: /* @__PURE__ */ x(y, { className: "h-12 w-12" }),
|
|
233
244
|
title: "No contracts found",
|
|
234
245
|
description: "Try adjusting your search criteria or create a new contract.",
|
|
@@ -243,6 +254,6 @@ function w() {
|
|
|
243
254
|
});
|
|
244
255
|
}
|
|
245
256
|
//#endregion
|
|
246
|
-
export {
|
|
257
|
+
export { T as AMCManagementPage };
|
|
247
258
|
|
|
248
259
|
//# sourceMappingURL=AMCManagementPage.js.map
|