@burdenoff/microfe-housingvista 2026.709.2 → 2026.709.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/housingvista/HousingVistaRoutes.d.ts.map +1 -1
  2. package/dist/housingvista/HousingVistaRoutes.js +136 -37
  3. package/dist/housingvista/HousingVistaRoutes.js.map +1 -1
  4. package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts +1 -1
  5. package/dist/housingvista/hooks/useHousingVistaAnalytics.d.ts.map +1 -1
  6. package/dist/housingvista/hooks/useHousingVistaAnalytics.js +4 -4
  7. package/dist/housingvista/hooks/useHousingVistaAnalytics.js.map +1 -1
  8. package/dist/housingvista/pages/amc/AMCManagementPage.d.ts.map +1 -1
  9. package/dist/housingvista/pages/amc/AMCManagementPage.js +62 -60
  10. package/dist/housingvista/pages/amc/AMCManagementPage.js.map +1 -1
  11. package/dist/housingvista/pages/assets/AssetDetailPage.d.ts.map +1 -1
  12. package/dist/housingvista/pages/assets/AssetDetailPage.js +141 -138
  13. package/dist/housingvista/pages/assets/AssetDetailPage.js.map +1 -1
  14. package/dist/housingvista/pages/assets/AssetManagementPage.d.ts.map +1 -1
  15. package/dist/housingvista/pages/assets/AssetManagementPage.js +193 -191
  16. package/dist/housingvista/pages/assets/AssetManagementPage.js.map +1 -1
  17. package/dist/housingvista/pages/chat/ChatPage.d.ts.map +1 -1
  18. package/dist/housingvista/pages/chat/ChatPage.js +115 -113
  19. package/dist/housingvista/pages/chat/ChatPage.js.map +1 -1
  20. package/dist/housingvista/pages/finance/HomeLoanDetailPage.d.ts.map +1 -1
  21. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js +152 -149
  22. package/dist/housingvista/pages/finance/HomeLoanDetailPage.js.map +1 -1
  23. package/dist/housingvista/pages/finance/HomeLoansPage.d.ts.map +1 -1
  24. package/dist/housingvista/pages/finance/HomeLoansPage.js +141 -139
  25. package/dist/housingvista/pages/finance/HomeLoansPage.js.map +1 -1
  26. package/dist/housingvista/pages/investments/InvestmentDetailPage.d.ts.map +1 -1
  27. package/dist/housingvista/pages/investments/InvestmentDetailPage.js +290 -287
  28. package/dist/housingvista/pages/investments/InvestmentDetailPage.js.map +1 -1
  29. package/dist/housingvista/pages/investments/InvestmentsPage.d.ts.map +1 -1
  30. package/dist/housingvista/pages/investments/InvestmentsPage.js +64 -62
  31. package/dist/housingvista/pages/investments/InvestmentsPage.js.map +1 -1
  32. package/dist/housingvista/pages/legal/LegalPage.d.ts.map +1 -1
  33. package/dist/housingvista/pages/legal/LegalPage.js +95 -93
  34. package/dist/housingvista/pages/legal/LegalPage.js.map +1 -1
  35. package/dist/housingvista/pages/legal/LegalServiceDetailPage.d.ts.map +1 -1
  36. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js +129 -126
  37. package/dist/housingvista/pages/legal/LegalServiceDetailPage.js.map +1 -1
  38. package/dist/housingvista/pages/market/AreaInsightsPage.d.ts.map +1 -1
  39. package/dist/housingvista/pages/market/AreaInsightsPage.js +99 -97
  40. package/dist/housingvista/pages/market/AreaInsightsPage.js.map +1 -1
  41. package/dist/housingvista/pages/market/MarketAnalyticsPage.d.ts.map +1 -1
  42. package/dist/housingvista/pages/market/MarketAnalyticsPage.js +138 -136
  43. package/dist/housingvista/pages/market/MarketAnalyticsPage.js.map +1 -1
  44. package/dist/housingvista/pages/marketplace/MarketplacePage.d.ts.map +1 -1
  45. package/dist/housingvista/pages/marketplace/MarketplacePage.js +99 -97
  46. package/dist/housingvista/pages/marketplace/MarketplacePage.js.map +1 -1
  47. package/dist/housingvista/pages/marketplace/ServiceDetailPage.d.ts.map +1 -1
  48. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js +137 -134
  49. package/dist/housingvista/pages/marketplace/ServiceDetailPage.js.map +1 -1
  50. package/dist/housingvista/pages/offers/OffersPage.d.ts.map +1 -1
  51. package/dist/housingvista/pages/offers/OffersPage.js +94 -92
  52. package/dist/housingvista/pages/offers/OffersPage.js.map +1 -1
  53. package/dist/housingvista/pages/properties/AddPropertyPage.d.ts.map +1 -1
  54. package/dist/housingvista/pages/properties/AddPropertyPage.js +280 -279
  55. package/dist/housingvista/pages/properties/AddPropertyPage.js.map +1 -1
  56. package/dist/housingvista/pages/rental/RentalManagementPage.d.ts.map +1 -1
  57. package/dist/housingvista/pages/rental/RentalManagementPage.js +153 -151
  58. package/dist/housingvista/pages/rental/RentalManagementPage.js.map +1 -1
  59. package/dist/housingvista/pages/settings/ProfilePage.d.ts.map +1 -1
  60. package/dist/housingvista/pages/settings/ProfilePage.js +52 -50
  61. package/dist/housingvista/pages/settings/ProfilePage.js.map +1 -1
  62. package/dist/housingvista/pages/settings/SettingsPage.d.ts.map +1 -1
  63. package/dist/housingvista/pages/settings/SettingsPage.js +54 -52
  64. package/dist/housingvista/pages/settings/SettingsPage.js.map +1 -1
  65. package/dist/housingvista/pages/shortlist/ShortlistPage.d.ts.map +1 -1
  66. package/dist/housingvista/pages/shortlist/ShortlistPage.js +43 -41
  67. package/dist/housingvista/pages/shortlist/ShortlistPage.js.map +1 -1
  68. package/dist/housingvista/pages/transactions/TransactionDetailPage.d.ts.map +1 -1
  69. package/dist/housingvista/pages/transactions/TransactionDetailPage.js +211 -208
  70. package/dist/housingvista/pages/transactions/TransactionDetailPage.js.map +1 -1
  71. package/dist/housingvista/pages/transactions/TransactionsPage.d.ts.map +1 -1
  72. package/dist/housingvista/pages/transactions/TransactionsPage.js +85 -83
  73. package/dist/housingvista/pages/transactions/TransactionsPage.js.map +1 -1
  74. package/dist/housingvista/pages/verification/VerificationDetailPage.d.ts.map +1 -1
  75. package/dist/housingvista/pages/verification/VerificationDetailPage.js +25 -22
  76. package/dist/housingvista/pages/verification/VerificationDetailPage.js.map +1 -1
  77. package/dist/housingvista/pages/verification/VerificationPage.d.ts.map +1 -1
  78. package/dist/housingvista/pages/verification/VerificationPage.js +123 -121
  79. package/dist/housingvista/pages/verification/VerificationPage.js.map +1 -1
  80. package/dist/housingvista/pages/viewings/ViewingsPage.d.ts.map +1 -1
  81. package/dist/housingvista/pages/viewings/ViewingsPage.js +128 -126
  82. package/dist/housingvista/pages/viewings/ViewingsPage.js.map +1 -1
  83. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MarketAnalyticsPage.js","names":[],"sources":["../../../../src/housingvista/pages/market/MarketAnalyticsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { TrendingUp, TrendingDown, IndianRupee, Building, Gauge, ArrowUpRight, ArrowDownRight } from 'lucide-react';\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n AreaChart,\n Area,\n BarChart,\n Bar,\n} from 'recharts';\nimport { EmphasisPanel, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, StatCard, ChartCard, DataTable } from '../../components';\nimport type { Column } from '../../components';\nimport { useMarketTrends } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn, formatCurrency, formatINRCompact } from '../../utils/helpers';\nimport type { MarketTrend } from '../../types';\n\n// Theme-aware recharts colors: `var(--color-chart-*)` resolves to the semantic\n// chart tokens in both light and dark themes (the previous `var(--color-chart-1)`\n// wrapped an oklch value and rendered invalid).\nconst CHART = {\n price: 'var(--color-chart-1)',\n rent: 'var(--color-chart-2)',\n demand: 'var(--color-chart-1)',\n supply: 'var(--color-chart-3)',\n} as const;\n\nconst TOOLTIP_CONTENT_STYLE = {\n backgroundColor: 'var(--color-bg-elevated)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: '0.5rem',\n fontSize: '0.75rem',\n} as const;\nconst TOOLTIP_LABEL_STYLE = { color: 'var(--color-text-primary)' } as const;\n\nexport function MarketAnalyticsPage() {\n const pagination = useServerPagination(10);\n const { data: trends, loading } = useMarketTrends(pagination.pagination);\n const [chartType, setChartType] = useState<'price' | 'rent' | 'demand'>('price');\n\n // Aggregate stats derived directly from the latest real market-trend record.\n const stats = useMemo(() => {\n if (trends.length === 0) return { avgPrice: 0, priceChange: 0, avgRent: 0, demandIndex: 0 };\n const latest = trends[trends.length - 1];\n return {\n avgPrice: latest.avgPrice,\n priceChange: latest.priceChangePercent,\n avgRent: latest.avgRent,\n demandIndex: latest.demandIndex,\n };\n }, [trends]);\n\n // Format chart data for month labels\n const chartData = useMemo(() => {\n return trends.map((t) => ({\n ...t,\n monthLabel: new Date(t.month + '-01').toLocaleDateString('en-US', { month: 'short', year: '2-digit' }),\n }));\n }, [trends]);\n\n // Table columns\n const columns: Column<MarketTrend & { monthLabel: string }>[] = [\n {\n key: 'monthLabel',\n header: 'Month',\n render: (item) => <span className=\"font-medium text-text-primary\">{item.monthLabel}</span>,\n },\n {\n key: 'avgPrice',\n header: 'Avg Price',\n render: (item) => <span className=\"text-text-primary\">{formatINRCompact(item.avgPrice)}</span>,\n },\n {\n key: 'avgRent',\n header: 'Avg Rent',\n render: (item) => <span className=\"text-text-primary\">{formatINRCompact(item.avgRent)}</span>,\n },\n {\n key: 'priceChangePercent',\n header: 'Change %',\n render: (item) => (\n <span\n className={cn(\n 'inline-flex items-center gap-0.5 text-xs font-medium',\n item.priceChangePercent >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {item.priceChangePercent >= 0 ? <ArrowUpRight className=\"h-3 w-3\" /> : <ArrowDownRight className=\"h-3 w-3\" />}\n {item.priceChangePercent > 0 ? '+' : ''}\n {item.priceChangePercent}%\n </span>\n ),\n },\n {\n key: 'demandIndex',\n header: 'Demand',\n render: (item) => (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-1.5 w-16 rounded-full bg-bg-sunken\">\n <div className=\"h-full rounded-full bg-chart-1\" style={{ width: `${item.demandIndex}%` }} />\n </div>\n <span className=\"text-xs text-text-secondary\">{item.demandIndex}</span>\n </div>\n ),\n },\n {\n key: 'supplyIndex',\n header: 'Supply',\n render: (item) => (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-1.5 w-16 rounded-full bg-bg-sunken\">\n <div className=\"h-full rounded-full bg-chart-3\" style={{ width: `${item.supplyIndex}%` }} />\n </div>\n <span className=\"text-xs text-text-secondary\">{item.supplyIndex}</span>\n </div>\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"Market Analytics\"\n description=\"Track market trends, price movements, and demand-supply dynamics\"\n purpose=\"Read the market before you act. Watch how prices, rents, demand, and supply move over time so you can time a purchase, set the right asking price, or spot a cooling or heating neighborhood early.\"\n >\n <NextSteps\n storageKey=\"housingvista-market-analytics\"\n steps={[\n {\n id: 'rent-trend',\n label: 'Check the rent trend',\n description: 'Switch the chart to Rent to see how rental rates are moving.',\n onClick: () => setChartType('rent'),\n },\n {\n id: 'demand',\n label: 'Compare demand vs supply',\n description: 'See where the market favors buyers or sellers.',\n onClick: () => setChartType('demand'),\n },\n {\n id: 'monthly',\n label: 'Open the monthly comparison',\n description: 'Review the full month-by-month breakdown in the table.',\n href: '#market-monthly-comparison',\n },\n ]}\n />\n\n {/* Stats Row — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label=\"Average Price\"\n value={formatINRCompact(stats.avgPrice)}\n icon={<IndianRupee className=\"h-5 w-5 text-accent-blue\" />}\n trend={stats.priceChange >= 0 ? 'up' : 'down'}\n change={stats.priceChange}\n featured\n />\n <StatCard\n label=\"Price Change (YoY)\"\n value={`${stats.priceChange >= 0 ? '+' : ''}${stats.priceChange}%`}\n icon={\n stats.priceChange >= 0 ? (\n <TrendingUp className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <TrendingDown className=\"h-5 w-5 text-status-error-text\" />\n )\n }\n />\n <StatCard\n label=\"Average Rent\"\n value={formatINRCompact(stats.avgRent)}\n icon={<Building className=\"h-5 w-5 text-accent-purple\" />}\n />\n <StatCard\n label=\"Demand Index\"\n value={stats.demandIndex}\n unit=\"/ 100\"\n icon={<Gauge className=\"h-5 w-5 text-status-success-text\" />}\n />\n </div>\n </EmphasisPanel>\n\n {/* Charts — trend (toggle) alongside demand-vs-supply, like the concept */}\n <div className=\"grid gap-6 xl:grid-cols-3\">\n <ChartCard\n className=\"xl:col-span-2\"\n title=\"Market Trends\"\n description=\"Monthly price, rent, and demand trends\"\n actions={\n <div className=\"flex gap-1\">\n {(['price', 'rent', 'demand'] as const).map((t) => (\n <button\n key={t}\n onClick={() => setChartType(t)}\n aria-pressed={chartType === t}\n className={cn(\n 'rounded-md px-2.5 py-1 text-xs font-medium transition-colors capitalize',\n chartType === t\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken'\n )}\n >\n {t}\n </button>\n ))}\n </div>\n }\n >\n <div className=\"h-72\">\n {chartData.length === 0 ? (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">\n No trend data yet.\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n {chartType === 'price' ? (\n <AreaChart data={chartData}>\n <defs>\n <linearGradient id=\"priceGrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"5%\" stopColor={CHART.price} stopOpacity={0.3} />\n <stop offset=\"95%\" stopColor={CHART.price} stopOpacity={0} />\n </linearGradient>\n </defs>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis\n tick={{ fontSize: 11, fill: 'currentColor' }}\n tickFormatter={(v) => formatINRCompact(v)}\n width={64}\n className=\"text-text-secondary\"\n />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n formatter={(value: number) => [formatCurrency(value), 'Avg Price']}\n />\n <Area\n type=\"monotone\"\n dataKey=\"avgPrice\"\n stroke={CHART.price}\n fill=\"url(#priceGrad)\"\n strokeWidth={2}\n />\n </AreaChart>\n ) : chartType === 'rent' ? (\n <LineChart data={chartData}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis\n tick={{ fontSize: 11, fill: 'currentColor' }}\n tickFormatter={(v) => formatINRCompact(v)}\n width={64}\n className=\"text-text-secondary\"\n />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n formatter={(value: number) => [formatCurrency(value), 'Avg Rent']}\n />\n <Line type=\"monotone\" dataKey=\"avgRent\" stroke={CHART.rent} strokeWidth={2} dot={{ r: 3 }} />\n </LineChart>\n ) : (\n <LineChart data={chartData}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis tick={{ fontSize: 11, fill: 'currentColor' }} className=\"text-text-secondary\" />\n <Tooltip contentStyle={TOOLTIP_CONTENT_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend wrapperStyle={{ fontSize: '0.75rem' }} />\n <Line\n type=\"monotone\"\n dataKey=\"demandIndex\"\n stroke={CHART.demand}\n name=\"Demand\"\n strokeWidth={2}\n dot={{ r: 3 }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"supplyIndex\"\n stroke={CHART.supply}\n name=\"Supply\"\n strokeWidth={2}\n dot={{ r: 3 }}\n />\n </LineChart>\n )}\n </ResponsiveContainer>\n )}\n </div>\n </ChartCard>\n\n <ChartCard title=\"Demand vs Supply\" description=\"Monthly demand & supply index\">\n <div className=\"h-72\">\n {chartData.length === 0 ? (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">No data yet.</div>\n ) : (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={chartData} barGap={2}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" vertical={false} />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis tick={{ fontSize: 11, fill: 'currentColor' }} className=\"text-text-secondary\" />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n cursor={{ fill: 'var(--color-bg-sunken)', opacity: 0.4 }}\n />\n <Legend wrapperStyle={{ fontSize: '0.75rem' }} />\n <Bar dataKey=\"demandIndex\" name=\"Demand\" fill={CHART.demand} radius={[3, 3, 0, 0]} />\n <Bar dataKey=\"supplyIndex\" name=\"Supply\" fill={CHART.supply} radius={[3, 3, 0, 0]} />\n </BarChart>\n </ResponsiveContainer>\n )}\n </div>\n </ChartCard>\n </div>\n\n {/* Market Comparison Table */}\n <div id=\"market-monthly-comparison\" className=\"scroll-mt-6\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Monthly Comparison</h2>\n <DataTable\n columns={columns}\n data={chartData}\n keyField=\"month\"\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: trends.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MarketAnalyticsPage.js","names":[],"sources":["../../../../src/housingvista/pages/market/MarketAnalyticsPage.tsx"],"sourcesContent":["import { useState, useMemo } from 'react';\nimport { TrendingUp, TrendingDown, IndianRupee, Building, Gauge, ArrowUpRight, ArrowDownRight } from 'lucide-react';\nimport {\n LineChart,\n Line,\n XAxis,\n YAxis,\n CartesianGrid,\n Tooltip,\n ResponsiveContainer,\n Legend,\n AreaChart,\n Area,\n BarChart,\n Bar,\n} from 'recharts';\nimport { EmphasisPanel, NextSteps } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, StatCard, ChartCard, DataTable } from '../../components';\nimport type { Column } from '../../components';\nimport { useMarketTrends } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn, formatCurrency, formatINRCompact } from '../../utils/helpers';\nimport type { MarketTrend } from '../../types';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\n// Theme-aware recharts colors: `var(--color-chart-*)` resolves to the semantic\n// chart tokens in both light and dark themes (the previous `var(--color-chart-1)`\n// wrapped an oklch value and rendered invalid).\nconst CHART = {\n price: 'var(--color-chart-1)',\n rent: 'var(--color-chart-2)',\n demand: 'var(--color-chart-1)',\n supply: 'var(--color-chart-3)',\n} as const;\n\nconst TOOLTIP_CONTENT_STYLE = {\n backgroundColor: 'var(--color-bg-elevated)',\n border: '1px solid var(--color-border-seam)',\n borderRadius: '0.5rem',\n fontSize: '0.75rem',\n} as const;\nconst TOOLTIP_LABEL_STYLE = { color: 'var(--color-text-primary)' } as const;\n\nexport function MarketAnalyticsPage() {\n useTrackPageView('housingvista.market_analytics.viewed');\n const pagination = useServerPagination(10);\n const { data: trends, loading } = useMarketTrends(pagination.pagination);\n const [chartType, setChartType] = useState<'price' | 'rent' | 'demand'>('price');\n\n // Aggregate stats derived directly from the latest real market-trend record.\n const stats = useMemo(() => {\n if (trends.length === 0) return { avgPrice: 0, priceChange: 0, avgRent: 0, demandIndex: 0 };\n const latest = trends[trends.length - 1];\n return {\n avgPrice: latest.avgPrice,\n priceChange: latest.priceChangePercent,\n avgRent: latest.avgRent,\n demandIndex: latest.demandIndex,\n };\n }, [trends]);\n\n // Format chart data for month labels\n const chartData = useMemo(() => {\n return trends.map((t) => ({\n ...t,\n monthLabel: new Date(t.month + '-01').toLocaleDateString('en-US', { month: 'short', year: '2-digit' }),\n }));\n }, [trends]);\n\n // Table columns\n const columns: Column<MarketTrend & { monthLabel: string }>[] = [\n {\n key: 'monthLabel',\n header: 'Month',\n render: (item) => <span className=\"font-medium text-text-primary\">{item.monthLabel}</span>,\n },\n {\n key: 'avgPrice',\n header: 'Avg Price',\n render: (item) => <span className=\"text-text-primary\">{formatINRCompact(item.avgPrice)}</span>,\n },\n {\n key: 'avgRent',\n header: 'Avg Rent',\n render: (item) => <span className=\"text-text-primary\">{formatINRCompact(item.avgRent)}</span>,\n },\n {\n key: 'priceChangePercent',\n header: 'Change %',\n render: (item) => (\n <span\n className={cn(\n 'inline-flex items-center gap-0.5 text-xs font-medium',\n item.priceChangePercent >= 0 ? 'text-status-success-text' : 'text-status-error-text'\n )}\n >\n {item.priceChangePercent >= 0 ? <ArrowUpRight className=\"h-3 w-3\" /> : <ArrowDownRight className=\"h-3 w-3\" />}\n {item.priceChangePercent > 0 ? '+' : ''}\n {item.priceChangePercent}%\n </span>\n ),\n },\n {\n key: 'demandIndex',\n header: 'Demand',\n render: (item) => (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-1.5 w-16 rounded-full bg-bg-sunken\">\n <div className=\"h-full rounded-full bg-chart-1\" style={{ width: `${item.demandIndex}%` }} />\n </div>\n <span className=\"text-xs text-text-secondary\">{item.demandIndex}</span>\n </div>\n ),\n },\n {\n key: 'supplyIndex',\n header: 'Supply',\n render: (item) => (\n <div className=\"flex items-center gap-2\">\n <div className=\"h-1.5 w-16 rounded-full bg-bg-sunken\">\n <div className=\"h-full rounded-full bg-chart-3\" style={{ width: `${item.supplyIndex}%` }} />\n </div>\n <span className=\"text-xs text-text-secondary\">{item.supplyIndex}</span>\n </div>\n ),\n },\n ];\n\n return (\n <PageLayout\n title=\"Market Analytics\"\n description=\"Track market trends, price movements, and demand-supply dynamics\"\n purpose=\"Read the market before you act. Watch how prices, rents, demand, and supply move over time so you can time a purchase, set the right asking price, or spot a cooling or heating neighborhood early.\"\n >\n <NextSteps\n storageKey=\"housingvista-market-analytics\"\n steps={[\n {\n id: 'rent-trend',\n label: 'Check the rent trend',\n description: 'Switch the chart to Rent to see how rental rates are moving.',\n onClick: () => setChartType('rent'),\n },\n {\n id: 'demand',\n label: 'Compare demand vs supply',\n description: 'See where the market favors buyers or sellers.',\n onClick: () => setChartType('demand'),\n },\n {\n id: 'monthly',\n label: 'Open the monthly comparison',\n description: 'Review the full month-by-month breakdown in the table.',\n href: '#market-monthly-comparison',\n },\n ]}\n />\n\n {/* Stats Row — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-4\">\n <StatCard\n label=\"Average Price\"\n value={formatINRCompact(stats.avgPrice)}\n icon={<IndianRupee className=\"h-5 w-5 text-accent-blue\" />}\n trend={stats.priceChange >= 0 ? 'up' : 'down'}\n change={stats.priceChange}\n featured\n />\n <StatCard\n label=\"Price Change (YoY)\"\n value={`${stats.priceChange >= 0 ? '+' : ''}${stats.priceChange}%`}\n icon={\n stats.priceChange >= 0 ? (\n <TrendingUp className=\"h-5 w-5 text-status-success-text\" />\n ) : (\n <TrendingDown className=\"h-5 w-5 text-status-error-text\" />\n )\n }\n />\n <StatCard\n label=\"Average Rent\"\n value={formatINRCompact(stats.avgRent)}\n icon={<Building className=\"h-5 w-5 text-accent-purple\" />}\n />\n <StatCard\n label=\"Demand Index\"\n value={stats.demandIndex}\n unit=\"/ 100\"\n icon={<Gauge className=\"h-5 w-5 text-status-success-text\" />}\n />\n </div>\n </EmphasisPanel>\n\n {/* Charts — trend (toggle) alongside demand-vs-supply, like the concept */}\n <div className=\"grid gap-6 xl:grid-cols-3\">\n <ChartCard\n className=\"xl:col-span-2\"\n title=\"Market Trends\"\n description=\"Monthly price, rent, and demand trends\"\n actions={\n <div className=\"flex gap-1\">\n {(['price', 'rent', 'demand'] as const).map((t) => (\n <button\n key={t}\n onClick={() => setChartType(t)}\n aria-pressed={chartType === t}\n className={cn(\n 'rounded-md px-2.5 py-1 text-xs font-medium transition-colors capitalize',\n chartType === t\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken'\n )}\n >\n {t}\n </button>\n ))}\n </div>\n }\n >\n <div className=\"h-72\">\n {chartData.length === 0 ? (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">\n No trend data yet.\n </div>\n ) : (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n {chartType === 'price' ? (\n <AreaChart data={chartData}>\n <defs>\n <linearGradient id=\"priceGrad\" x1=\"0\" y1=\"0\" x2=\"0\" y2=\"1\">\n <stop offset=\"5%\" stopColor={CHART.price} stopOpacity={0.3} />\n <stop offset=\"95%\" stopColor={CHART.price} stopOpacity={0} />\n </linearGradient>\n </defs>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis\n tick={{ fontSize: 11, fill: 'currentColor' }}\n tickFormatter={(v) => formatINRCompact(v)}\n width={64}\n className=\"text-text-secondary\"\n />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n formatter={(value: number) => [formatCurrency(value), 'Avg Price']}\n />\n <Area\n type=\"monotone\"\n dataKey=\"avgPrice\"\n stroke={CHART.price}\n fill=\"url(#priceGrad)\"\n strokeWidth={2}\n />\n </AreaChart>\n ) : chartType === 'rent' ? (\n <LineChart data={chartData}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis\n tick={{ fontSize: 11, fill: 'currentColor' }}\n tickFormatter={(v) => formatINRCompact(v)}\n width={64}\n className=\"text-text-secondary\"\n />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n formatter={(value: number) => [formatCurrency(value), 'Avg Rent']}\n />\n <Line type=\"monotone\" dataKey=\"avgRent\" stroke={CHART.rent} strokeWidth={2} dot={{ r: 3 }} />\n </LineChart>\n ) : (\n <LineChart data={chartData}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis tick={{ fontSize: 11, fill: 'currentColor' }} className=\"text-text-secondary\" />\n <Tooltip contentStyle={TOOLTIP_CONTENT_STYLE} labelStyle={TOOLTIP_LABEL_STYLE} />\n <Legend wrapperStyle={{ fontSize: '0.75rem' }} />\n <Line\n type=\"monotone\"\n dataKey=\"demandIndex\"\n stroke={CHART.demand}\n name=\"Demand\"\n strokeWidth={2}\n dot={{ r: 3 }}\n />\n <Line\n type=\"monotone\"\n dataKey=\"supplyIndex\"\n stroke={CHART.supply}\n name=\"Supply\"\n strokeWidth={2}\n dot={{ r: 3 }}\n />\n </LineChart>\n )}\n </ResponsiveContainer>\n )}\n </div>\n </ChartCard>\n\n <ChartCard title=\"Demand vs Supply\" description=\"Monthly demand & supply index\">\n <div className=\"h-72\">\n {chartData.length === 0 ? (\n <div className=\"flex h-full items-center justify-center text-sm text-text-secondary\">No data yet.</div>\n ) : (\n <ResponsiveContainer width=\"100%\" height=\"100%\">\n <BarChart data={chartData} barGap={2}>\n <CartesianGrid strokeDasharray=\"3 3\" className=\"stroke-border\" vertical={false} />\n <XAxis\n dataKey=\"monthLabel\"\n tick={{ fontSize: 11, fill: 'currentColor' }}\n className=\"text-text-secondary\"\n />\n <YAxis tick={{ fontSize: 11, fill: 'currentColor' }} className=\"text-text-secondary\" />\n <Tooltip\n contentStyle={TOOLTIP_CONTENT_STYLE}\n labelStyle={TOOLTIP_LABEL_STYLE}\n cursor={{ fill: 'var(--color-bg-sunken)', opacity: 0.4 }}\n />\n <Legend wrapperStyle={{ fontSize: '0.75rem' }} />\n <Bar dataKey=\"demandIndex\" name=\"Demand\" fill={CHART.demand} radius={[3, 3, 0, 0]} />\n <Bar dataKey=\"supplyIndex\" name=\"Supply\" fill={CHART.supply} radius={[3, 3, 0, 0]} />\n </BarChart>\n </ResponsiveContainer>\n )}\n </div>\n </ChartCard>\n </div>\n\n {/* Market Comparison Table */}\n <div id=\"market-monthly-comparison\" className=\"scroll-mt-6\">\n <h2 className=\"mb-3 text-lg font-semibold text-text-primary\">Monthly Comparison</h2>\n <DataTable\n columns={columns}\n data={chartData}\n keyField=\"month\"\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: trends.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplacePage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/marketplace/MarketplacePage.tsx"],"names":[],"mappings":"AAoKA,wBAAgB,eAAe,gCAyH9B"}
1
+ {"version":3,"file":"MarketplacePage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/marketplace/MarketplacePage.tsx"],"names":[],"mappings":"AAqKA,wBAAgB,eAAe,gCA0H9B"}
@@ -3,16 +3,17 @@ import { PageLayout as t } from "../../components/PageLayout.js";
3
3
  import { EmptyState as n } from "../../components/EmptyState.js";
4
4
  import { FilterBar as r } from "../../components/FilterBar.js";
5
5
  import { LoadingSkeleton as i } from "../../components/LoadingSkeleton.js";
6
- import { useMarketplaceServices as a } from "../../hooks/index.js";
6
+ import { useTrackPageView as a } from "../../hooks/useHousingVistaAnalytics.js";
7
+ import { useMarketplaceServices as o } from "../../hooks/index.js";
7
8
  import "../../components/index.js";
8
- import { useServerPagination as o } from "../../hooks/useServerPagination.js";
9
- import { useEffect as s, useMemo as c, useState as l } from "react";
10
- import { CheckCircle as u, Clock as d, MapPin as f, MessageCircle as p, Paintbrush as m, Phone as h, Shield as g, ShieldCheck as _, SprayCanIcon as v, Star as y, Trees as b, Wrench as x, Zap as S } from "lucide-react";
11
- import { useNavigate as C } from "react-router-dom";
12
- import { Fragment as w, jsx as T, jsxs as E } from "react/jsx-runtime";
13
- import { EmphasisPanel as D, NextSteps as O, Pagination as k } from "@burdenoff/fe-libs/ui";
9
+ import { useServerPagination as s } from "../../hooks/useServerPagination.js";
10
+ import { useEffect as c, useMemo as l, useState as u } from "react";
11
+ import { CheckCircle as d, Clock as f, MapPin as p, MessageCircle as m, Paintbrush as h, Phone as g, Shield as _, ShieldCheck as v, SprayCanIcon as y, Star as b, Trees as x, Wrench as S, Zap as C } from "lucide-react";
12
+ import { useNavigate as w } from "react-router-dom";
13
+ import { Fragment as T, jsx as E, jsxs as D } from "react/jsx-runtime";
14
+ import { EmphasisPanel as O, NextSteps as k, Pagination as A } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/housingvista/pages/marketplace/MarketplacePage.tsx
15
- var A = 9, j = [
16
+ var j = 9, M = [
16
17
  {
17
18
  value: "all",
18
19
  label: "All"
@@ -42,74 +43,74 @@ var A = 9, j = [
42
43
  label: "Landscaping"
43
44
  }
44
45
  ];
45
- function M(e) {
46
+ function N(e) {
46
47
  switch (e) {
47
- case "repair": return /* @__PURE__ */ T(x, { className: "h-4 w-4" });
48
- case "maintenance": return /* @__PURE__ */ T(S, { className: "h-4 w-4" });
49
- case "cleaning": return /* @__PURE__ */ T(v, { className: "h-4 w-4" });
50
- case "renovation": return /* @__PURE__ */ T(m, { className: "h-4 w-4" });
51
- case "security": return /* @__PURE__ */ T(g, { className: "h-4 w-4" });
52
- case "landscaping": return /* @__PURE__ */ T(b, { className: "h-4 w-4" });
53
- case "pest_control": return /* @__PURE__ */ T(_, { className: "h-4 w-4" });
54
- default: return /* @__PURE__ */ T(x, { className: "h-4 w-4" });
48
+ case "repair": return /* @__PURE__ */ E(S, { className: "h-4 w-4" });
49
+ case "maintenance": return /* @__PURE__ */ E(C, { className: "h-4 w-4" });
50
+ case "cleaning": return /* @__PURE__ */ E(y, { className: "h-4 w-4" });
51
+ case "renovation": return /* @__PURE__ */ E(h, { className: "h-4 w-4" });
52
+ case "security": return /* @__PURE__ */ E(_, { className: "h-4 w-4" });
53
+ case "landscaping": return /* @__PURE__ */ E(x, { className: "h-4 w-4" });
54
+ case "pest_control": return /* @__PURE__ */ E(v, { className: "h-4 w-4" });
55
+ default: return /* @__PURE__ */ E(S, { className: "h-4 w-4" });
55
56
  }
56
57
  }
57
- function N({ rating: t }) {
58
- return /* @__PURE__ */ T("div", {
58
+ function P({ rating: t }) {
59
+ return /* @__PURE__ */ E("div", {
59
60
  className: "flex items-center gap-0.5 text-status-warning-text",
60
- children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ T(y, { className: e("h-3.5 w-3.5", r < Math.floor(t) ? "fill-current" : r < t ? "fill-current opacity-50" : "fill-none text-text-secondary/30") }, r))
61
+ children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ E(b, { className: e("h-3.5 w-3.5", r < Math.floor(t) ? "fill-current" : r < t ? "fill-current opacity-50" : "fill-none text-text-secondary/30") }, r))
61
62
  });
62
63
  }
63
- function P({ service: e }) {
64
- let t = C();
65
- return /* @__PURE__ */ E("div", {
64
+ function F({ service: e }) {
65
+ let t = w();
66
+ return /* @__PURE__ */ D("div", {
66
67
  className: "group flex flex-col overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2",
67
- children: [/* @__PURE__ */ E("div", {
68
+ children: [/* @__PURE__ */ D("div", {
68
69
  className: "relative aspect-[16/10] overflow-hidden bg-bg-sunken",
69
70
  children: [
70
- e.imageUrl ? /* @__PURE__ */ T("img", {
71
+ e.imageUrl ? /* @__PURE__ */ E("img", {
71
72
  src: e.imageUrl,
72
73
  alt: e.name,
73
74
  loading: "lazy",
74
75
  className: "h-full w-full object-cover"
75
- }) : /* @__PURE__ */ T("div", {
76
+ }) : /* @__PURE__ */ E("div", {
76
77
  className: "flex h-full w-full items-center justify-center bg-gradient-to-br from-accent-blue-subtle to-status-success-bg-subtle text-text-secondary/50",
77
- children: /* @__PURE__ */ T("span", {
78
+ children: /* @__PURE__ */ E("span", {
78
79
  className: "[&>svg]:h-10 [&>svg]:w-10",
79
- children: M(e.category)
80
+ children: N(e.category)
80
81
  })
81
82
  }),
82
- /* @__PURE__ */ E("span", {
83
+ /* @__PURE__ */ D("span", {
83
84
  className: "absolute left-3 top-3 inline-flex items-center gap-1 rounded-full bg-bg-surface/90 px-2 py-0.5 text-xs font-medium capitalize text-text-secondary shadow-elevation-1 backdrop-blur",
84
- children: [M(e.category), e.category.replace(/_/g, " ")]
85
+ children: [N(e.category), e.category.replace(/_/g, " ")]
85
86
  }),
86
- e.featured && /* @__PURE__ */ T("span", {
87
+ e.featured && /* @__PURE__ */ E("span", {
87
88
  className: "absolute right-3 top-3 rounded-full bg-status-warning-text px-2 py-0.5 text-xs font-semibold text-text-inverse shadow-elevation-1",
88
89
  children: "Featured"
89
90
  })
90
91
  ]
91
- }), /* @__PURE__ */ E("div", {
92
+ }), /* @__PURE__ */ D("div", {
92
93
  className: "flex flex-1 flex-col p-5",
93
94
  children: [
94
- /* @__PURE__ */ E("div", {
95
+ /* @__PURE__ */ D("div", {
95
96
  className: "mb-2",
96
- children: [/* @__PURE__ */ T("h3", {
97
+ children: [/* @__PURE__ */ E("h3", {
97
98
  className: "truncate text-sm font-semibold text-text-primary",
98
99
  children: e.name
99
- }), /* @__PURE__ */ T("p", {
100
+ }), /* @__PURE__ */ E("p", {
100
101
  className: "text-xs text-text-secondary",
101
102
  children: e.providerName
102
103
  })]
103
104
  }),
104
- /* @__PURE__ */ E("div", {
105
+ /* @__PURE__ */ D("div", {
105
106
  className: "mb-3 flex items-center gap-2",
106
107
  children: [
107
- /* @__PURE__ */ T(N, { rating: e.rating }),
108
- /* @__PURE__ */ T("span", {
108
+ /* @__PURE__ */ E(P, { rating: e.rating }),
109
+ /* @__PURE__ */ E("span", {
109
110
  className: "text-xs font-medium text-text-primary",
110
111
  children: e.rating
111
112
  }),
112
- /* @__PURE__ */ E("span", {
113
+ /* @__PURE__ */ D("span", {
113
114
  className: "text-xs text-text-secondary",
114
115
  children: [
115
116
  "(",
@@ -119,136 +120,137 @@ function P({ service: e }) {
119
120
  })
120
121
  ]
121
122
  }),
122
- /* @__PURE__ */ T("p", {
123
+ /* @__PURE__ */ E("p", {
123
124
  className: "mb-3 line-clamp-2 text-xs text-text-secondary",
124
125
  children: e.description
125
126
  }),
126
- /* @__PURE__ */ E("div", {
127
+ /* @__PURE__ */ D("div", {
127
128
  className: "mb-3 flex items-center justify-between text-xs",
128
- children: [/* @__PURE__ */ T("span", {
129
+ children: [/* @__PURE__ */ E("span", {
129
130
  className: "font-semibold text-text-primary",
130
131
  children: e.priceRange
131
- }), /* @__PURE__ */ E("span", {
132
+ }), /* @__PURE__ */ D("span", {
132
133
  className: "flex items-center gap-1 text-text-secondary",
133
- children: [/* @__PURE__ */ T(d, { className: "h-3 w-3" }), e.responseTime]
134
+ children: [/* @__PURE__ */ E(f, { className: "h-3 w-3" }), e.responseTime]
134
135
  })]
135
136
  }),
136
- /* @__PURE__ */ E("div", {
137
+ /* @__PURE__ */ D("div", {
137
138
  className: "mb-4 flex flex-wrap items-center gap-2",
138
- children: [e.verified && /* @__PURE__ */ E("span", {
139
+ children: [e.verified && /* @__PURE__ */ D("span", {
139
140
  className: "inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text",
140
- children: [/* @__PURE__ */ T(u, { className: "h-3 w-3" }), "Verified"]
141
- }), /* @__PURE__ */ E("span", {
141
+ children: [/* @__PURE__ */ E(d, { className: "h-3 w-3" }), "Verified"]
142
+ }), /* @__PURE__ */ D("span", {
142
143
  className: "inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs text-status-info-text",
143
144
  children: [
144
- /* @__PURE__ */ T(f, { className: "h-3 w-3" }),
145
+ /* @__PURE__ */ E(p, { className: "h-3 w-3" }),
145
146
  e.availableAreas.length,
146
147
  " area",
147
148
  e.availableAreas.length === 1 ? "" : "s"
148
149
  ]
149
150
  })]
150
151
  }),
151
- /* @__PURE__ */ E("div", {
152
+ /* @__PURE__ */ D("div", {
152
153
  className: "mt-auto flex items-center gap-2",
153
- children: [/* @__PURE__ */ E("button", {
154
+ children: [/* @__PURE__ */ D("button", {
154
155
  onClick: () => t(`../marketplace/${e.id}`),
155
156
  className: "flex-1 rounded-md bg-action-primary-bg px-3 py-2 text-xs font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover",
156
- children: [/* @__PURE__ */ T(h, { className: "mr-1 inline h-3 w-3" }), "Contact"]
157
- }), /* @__PURE__ */ T("button", {
157
+ children: [/* @__PURE__ */ E(g, { className: "mr-1 inline h-3 w-3" }), "Contact"]
158
+ }), /* @__PURE__ */ E("button", {
158
159
  "aria-label": `Message ${e.providerName}`,
159
160
  onClick: () => t(`../marketplace/${e.id}`),
160
161
  className: "rounded-md border border-border-subtle px-3 py-2 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken",
161
- children: /* @__PURE__ */ T(p, { className: "h-3 w-3" })
162
+ children: /* @__PURE__ */ E(m, { className: "h-3 w-3" })
162
163
  })]
163
164
  })
164
165
  ]
165
166
  })]
166
167
  });
167
168
  }
168
- function F() {
169
- let [u, d] = l(""), [f, p] = l(""), [m, h] = l("all"), g = o(A), { setPage: _ } = g;
170
- s(() => {
171
- let e = setTimeout(() => p(u), 300);
169
+ function I() {
170
+ a("housingvista.marketplace.viewed");
171
+ let [d, f] = u(""), [p, m] = u(""), [h, g] = u("all"), _ = s(j), { setPage: v } = _;
172
+ c(() => {
173
+ let e = setTimeout(() => m(d), 300);
172
174
  return () => clearTimeout(e);
173
- }, [u]);
174
- let v = c(() => {
175
+ }, [d]);
176
+ let y = l(() => {
175
177
  let e = {};
176
- return f.trim() && (e.search = f.trim()), m !== "all" && (e.category = m), Object.keys(e).length > 0 ? e : void 0;
177
- }, [f, m]);
178
- s(() => {
179
- _(1);
180
- }, [v, _]);
181
- let { data: y, loading: b } = a({
182
- filter: v,
183
- pagination: g.pagination
184
- }), x = y.length >= g.pageSize;
185
- return /* @__PURE__ */ E(t, {
178
+ return p.trim() && (e.search = p.trim()), h !== "all" && (e.category = h), Object.keys(e).length > 0 ? e : void 0;
179
+ }, [p, h]);
180
+ c(() => {
181
+ v(1);
182
+ }, [y, v]);
183
+ let { data: b, loading: x } = o({
184
+ filter: y,
185
+ pagination: _.pagination
186
+ }), S = b.length >= _.pageSize;
187
+ return /* @__PURE__ */ D(t, {
186
188
  title: "Service Marketplace",
187
189
  description: "Find trusted service providers for your property needs",
188
190
  purpose: "Hire vetted professionals — plumbers, electricians, cleaners, painters, security, and landscapers — to keep your properties in top shape. Browse by category, compare ratings and response times, then contact or message a provider directly.",
189
191
  children: [
190
- /* @__PURE__ */ T(D, {
192
+ /* @__PURE__ */ E(O, {
191
193
  className: "flex flex-wrap items-center gap-2 p-3",
192
- children: j.map((t) => /* @__PURE__ */ T("button", {
193
- onClick: () => h(t.value),
194
- className: e("rounded-full px-4 py-1.5 text-sm font-medium transition-colors", m === t.value ? "bg-action-primary-bg text-action-primary-text" : "border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary"),
194
+ children: M.map((t) => /* @__PURE__ */ E("button", {
195
+ onClick: () => g(t.value),
196
+ className: e("rounded-full px-4 py-1.5 text-sm font-medium transition-colors", h === t.value ? "bg-action-primary-bg text-action-primary-text" : "border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary"),
195
197
  children: t.label
196
198
  }, t.value))
197
199
  }),
198
- /* @__PURE__ */ T(r, {
199
- searchValue: u,
200
- onSearchChange: d,
200
+ /* @__PURE__ */ E(r, {
201
+ searchValue: d,
202
+ onSearchChange: f,
201
203
  searchPlaceholder: "Search services, providers..."
202
204
  }),
203
- /* @__PURE__ */ T(O, {
205
+ /* @__PURE__ */ E(k, {
204
206
  storageKey: "housingvista-marketplace",
205
207
  steps: [
206
208
  {
207
209
  id: "book-repair",
208
210
  label: "Fix something now",
209
211
  description: "Find a plumber or repair pro for an urgent issue.",
210
- onClick: () => h("repair")
212
+ onClick: () => g("repair")
211
213
  },
212
214
  {
213
215
  id: "book-cleaning",
214
216
  label: "Schedule a cleaning",
215
217
  description: "Get a property move-in or turnover ready.",
216
- onClick: () => h("cleaning")
218
+ onClick: () => g("cleaning")
217
219
  },
218
220
  {
219
221
  id: "see-featured",
220
222
  label: "Browse all providers",
221
223
  description: "Clear filters to compare every vetted professional.",
222
224
  onClick: () => {
223
- h("all"), d("");
225
+ g("all"), f("");
224
226
  }
225
227
  }
226
228
  ]
227
229
  }),
228
- /* @__PURE__ */ E("p", {
230
+ /* @__PURE__ */ D("p", {
229
231
  className: "text-sm text-text-secondary",
230
232
  children: [
231
- y.length,
233
+ b.length,
232
234
  " service",
233
- y.length === 1 ? "" : "s",
235
+ b.length === 1 ? "" : "s",
234
236
  " shown",
235
- g.page > 1 ? ` · page ${g.page}` : ""
237
+ _.page > 1 ? ` · page ${_.page}` : ""
236
238
  ]
237
239
  }),
238
- b ? /* @__PURE__ */ T(i, {
240
+ x ? /* @__PURE__ */ E(i, {
239
241
  variant: "card",
240
242
  count: 6
241
- }) : y.length > 0 ? /* @__PURE__ */ E(w, { children: [/* @__PURE__ */ T("div", {
243
+ }) : b.length > 0 ? /* @__PURE__ */ D(T, { children: [/* @__PURE__ */ E("div", {
242
244
  className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-3",
243
- children: y.map((e) => /* @__PURE__ */ T(P, { service: e }, e.id))
244
- }), /* @__PURE__ */ T(k, {
245
- page: g.page,
246
- pageSize: g.pageSize,
247
- hasNextPage: x,
248
- hasPreviousPage: g.page > 1,
249
- onPageChange: g.setPage,
250
- onPageSizeChange: g.setPageSize
251
- })] }) : /* @__PURE__ */ T(n, {
245
+ children: b.map((e) => /* @__PURE__ */ E(F, { service: e }, e.id))
246
+ }), /* @__PURE__ */ E(A, {
247
+ page: _.page,
248
+ pageSize: _.pageSize,
249
+ hasNextPage: S,
250
+ hasPreviousPage: _.page > 1,
251
+ onPageChange: _.setPage,
252
+ onPageSizeChange: _.setPageSize
253
+ })] }) : /* @__PURE__ */ E(n, {
252
254
  illustration: "empty-search",
253
255
  title: "No services found",
254
256
  description: "Try adjusting your search or category filter to find what you need."
@@ -257,6 +259,6 @@ function F() {
257
259
  });
258
260
  }
259
261
  //#endregion
260
- export { F as MarketplacePage };
262
+ export { I as MarketplacePage };
261
263
 
262
264
  //# sourceMappingURL=MarketplacePage.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplacePage.js","names":[],"sources":["../../../../src/housingvista/pages/marketplace/MarketplacePage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Star,\n Phone,\n MapPin,\n Shield,\n Wrench,\n Zap,\n SprayCanIcon,\n Paintbrush,\n ShieldCheck,\n Trees,\n CheckCircle,\n Clock,\n MessageCircle,\n} from 'lucide-react';\nimport { EmphasisPanel, NextSteps, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, EmptyState, LoadingSkeleton } from '../../components';\nimport { useMarketplaceServices, type MarketplaceServiceFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn } from '../../utils/helpers';\nimport type { MarketplaceService } from '../../types';\n\nconst PAGE_SIZE = 9;\n\nconst categories = [\n { value: 'all', label: 'All' },\n { value: 'repair', label: 'Plumbing' },\n { value: 'maintenance', label: 'Electrical' },\n { value: 'cleaning', label: 'Cleaning' },\n { value: 'renovation', label: 'Painting' },\n { value: 'security', label: 'Security' },\n { value: 'landscaping', label: 'Landscaping' },\n] as const;\n\nfunction getCategoryIcon(category: string) {\n switch (category) {\n case 'repair':\n return <Wrench className=\"h-4 w-4\" />;\n case 'maintenance':\n return <Zap className=\"h-4 w-4\" />;\n case 'cleaning':\n return <SprayCanIcon className=\"h-4 w-4\" />;\n case 'renovation':\n return <Paintbrush className=\"h-4 w-4\" />;\n case 'security':\n return <Shield className=\"h-4 w-4\" />;\n case 'landscaping':\n return <Trees className=\"h-4 w-4\" />;\n case 'pest_control':\n return <ShieldCheck className=\"h-4 w-4\" />;\n default:\n return <Wrench className=\"h-4 w-4\" />;\n }\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5 text-status-warning-text\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn(\n 'h-3.5 w-3.5',\n i < Math.floor(rating)\n ? 'fill-current'\n : i < rating\n ? 'fill-current opacity-50'\n : 'fill-none text-text-secondary/30'\n )}\n />\n ))}\n </div>\n );\n}\n\nfunction ServiceCard({ service }: { service: MarketplaceService }) {\n const navigate = useNavigate();\n\n return (\n <div className=\"group flex flex-col overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2\">\n {/* Image / branded placeholder + badges */}\n <div className=\"relative aspect-[16/10] overflow-hidden bg-bg-sunken\">\n {service.imageUrl ? (\n <img src={service.imageUrl} alt={service.name} loading=\"lazy\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-accent-blue-subtle to-status-success-bg-subtle text-text-secondary/50\">\n <span className=\"[&>svg]:h-10 [&>svg]:w-10\">{getCategoryIcon(service.category)}</span>\n </div>\n )}\n <span className=\"absolute left-3 top-3 inline-flex items-center gap-1 rounded-full bg-bg-surface/90 px-2 py-0.5 text-xs font-medium capitalize text-text-secondary shadow-elevation-1 backdrop-blur\">\n {getCategoryIcon(service.category)}\n {service.category.replace(/_/g, ' ')}\n </span>\n {service.featured && (\n <span className=\"absolute right-3 top-3 rounded-full bg-status-warning-text px-2 py-0.5 text-xs font-semibold text-text-inverse shadow-elevation-1\">\n Featured\n </span>\n )}\n </div>\n\n <div className=\"flex flex-1 flex-col p-5\">\n {/* Header */}\n <div className=\"mb-2\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{service.name}</h3>\n <p className=\"text-xs text-text-secondary\">{service.providerName}</p>\n </div>\n\n {/* Rating */}\n <div className=\"mb-3 flex items-center gap-2\">\n <RatingStars rating={service.rating} />\n <span className=\"text-xs font-medium text-text-primary\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">({service.reviewCount} reviews)</span>\n </div>\n\n {/* Description */}\n <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{service.description}</p>\n\n {/* Price + Response Time */}\n <div className=\"mb-3 flex items-center justify-between text-xs\">\n <span className=\"font-semibold text-text-primary\">{service.priceRange}</span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Clock className=\"h-3 w-3\" />\n {service.responseTime}\n </span>\n </div>\n\n {/* Availability + Verified */}\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">\n {service.verified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n <CheckCircle className=\"h-3 w-3\" />\n Verified\n </span>\n )}\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs text-status-info-text\">\n <MapPin className=\"h-3 w-3\" />\n {service.availableAreas.length} area{service.availableAreas.length !== 1 ? 's' : ''}\n </span>\n </div>\n\n {/* Actions */}\n <div className=\"mt-auto flex items-center gap-2\">\n <button\n onClick={() => navigate(`../marketplace/${service.id}`)}\n className=\"flex-1 rounded-md bg-action-primary-bg px-3 py-2 text-xs font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Phone className=\"mr-1 inline h-3 w-3\" />\n Contact\n </button>\n <button\n aria-label={`Message ${service.providerName}`}\n onClick={() => navigate(`../marketplace/${service.id}`)}\n className=\"rounded-md border border-border-subtle px-3 py-2 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <MessageCircle className=\"h-3 w-3\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport function MarketplacePage() {\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [activeCategory, setActiveCategory] = useState<string>('all');\n const pagination = useServerPagination(PAGE_SIZE);\n const { setPage } = pagination;\n\n // Debounce the search box so we don't refetch on every keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n // Server-side filter — category + search are resolved by the subgraph.\n const serverFilter = useMemo<MarketplaceServiceFilterInput | undefined>(() => {\n const filter: MarketplaceServiceFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (activeCategory !== 'all') filter.category = activeCategory;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, activeCategory]);\n\n // Reset to the first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: services, loading } = useMarketplaceServices({\n filter: serverFilter,\n pagination: pagination.pagination,\n });\n\n const hasNextPage = services.length >= pagination.pageSize;\n\n return (\n <PageLayout\n title=\"Service Marketplace\"\n description=\"Find trusted service providers for your property needs\"\n purpose=\"Hire vetted professionals — plumbers, electricians, cleaners, painters, security, and landscapers — to keep your properties in top shape. Browse by category, compare ratings and response times, then contact or message a provider directly.\"\n >\n {/* Category Tabs — primary control zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"flex flex-wrap items-center gap-2 p-3\">\n {categories.map((cat) => (\n <button\n key={cat.value}\n onClick={() => setActiveCategory(cat.value)}\n className={cn(\n 'rounded-full px-4 py-1.5 text-sm font-medium transition-colors',\n activeCategory === cat.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {cat.label}\n </button>\n ))}\n </EmphasisPanel>\n\n {/* Search */}\n <FilterBar searchValue={search} onSearchChange={setSearch} searchPlaceholder=\"Search services, providers...\" />\n\n <NextSteps\n storageKey=\"housingvista-marketplace\"\n steps={[\n {\n id: 'book-repair',\n label: 'Fix something now',\n description: 'Find a plumber or repair pro for an urgent issue.',\n onClick: () => setActiveCategory('repair'),\n },\n {\n id: 'book-cleaning',\n label: 'Schedule a cleaning',\n description: 'Get a property move-in or turnover ready.',\n onClick: () => setActiveCategory('cleaning'),\n },\n {\n id: 'see-featured',\n label: 'Browse all providers',\n description: 'Clear filters to compare every vetted professional.',\n onClick: () => {\n setActiveCategory('all');\n setSearch('');\n },\n },\n ]}\n />\n\n {/* Results Count */}\n <p className=\"text-sm text-text-secondary\">\n {services.length} service{services.length !== 1 ? 's' : ''} shown\n {pagination.page > 1 ? ` · page ${pagination.page}` : ''}\n </p>\n\n {/* Service Grid */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : services.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {services.map((service) => (\n <ServiceCard key={service.id} service={service} />\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No services found\"\n description=\"Try adjusting your search or category filter to find what you need.\"\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"MarketplacePage.js","names":[],"sources":["../../../../src/housingvista/pages/marketplace/MarketplacePage.tsx"],"sourcesContent":["import { useState, useEffect, useMemo } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport {\n Star,\n Phone,\n MapPin,\n Shield,\n Wrench,\n Zap,\n SprayCanIcon,\n Paintbrush,\n ShieldCheck,\n Trees,\n CheckCircle,\n Clock,\n MessageCircle,\n} from 'lucide-react';\nimport { EmphasisPanel, NextSteps, Pagination } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, EmptyState, LoadingSkeleton } from '../../components';\nimport { useMarketplaceServices, type MarketplaceServiceFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { cn } from '../../utils/helpers';\nimport type { MarketplaceService } from '../../types';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst PAGE_SIZE = 9;\n\nconst categories = [\n { value: 'all', label: 'All' },\n { value: 'repair', label: 'Plumbing' },\n { value: 'maintenance', label: 'Electrical' },\n { value: 'cleaning', label: 'Cleaning' },\n { value: 'renovation', label: 'Painting' },\n { value: 'security', label: 'Security' },\n { value: 'landscaping', label: 'Landscaping' },\n] as const;\n\nfunction getCategoryIcon(category: string) {\n switch (category) {\n case 'repair':\n return <Wrench className=\"h-4 w-4\" />;\n case 'maintenance':\n return <Zap className=\"h-4 w-4\" />;\n case 'cleaning':\n return <SprayCanIcon className=\"h-4 w-4\" />;\n case 'renovation':\n return <Paintbrush className=\"h-4 w-4\" />;\n case 'security':\n return <Shield className=\"h-4 w-4\" />;\n case 'landscaping':\n return <Trees className=\"h-4 w-4\" />;\n case 'pest_control':\n return <ShieldCheck className=\"h-4 w-4\" />;\n default:\n return <Wrench className=\"h-4 w-4\" />;\n }\n}\n\nfunction RatingStars({ rating }: { rating: number }) {\n return (\n <div className=\"flex items-center gap-0.5 text-status-warning-text\">\n {Array.from({ length: 5 }).map((_, i) => (\n <Star\n key={i}\n className={cn(\n 'h-3.5 w-3.5',\n i < Math.floor(rating)\n ? 'fill-current'\n : i < rating\n ? 'fill-current opacity-50'\n : 'fill-none text-text-secondary/30'\n )}\n />\n ))}\n </div>\n );\n}\n\nfunction ServiceCard({ service }: { service: MarketplaceService }) {\n const navigate = useNavigate();\n\n return (\n <div className=\"group flex flex-col overflow-hidden rounded-card border border-border-seam bg-bg-surface shadow-elevation-1 transition-[box-shadow,border-color] hover:border-border-strong hover:shadow-elevation-2\">\n {/* Image / branded placeholder + badges */}\n <div className=\"relative aspect-[16/10] overflow-hidden bg-bg-sunken\">\n {service.imageUrl ? (\n <img src={service.imageUrl} alt={service.name} loading=\"lazy\" className=\"h-full w-full object-cover\" />\n ) : (\n <div className=\"flex h-full w-full items-center justify-center bg-gradient-to-br from-accent-blue-subtle to-status-success-bg-subtle text-text-secondary/50\">\n <span className=\"[&>svg]:h-10 [&>svg]:w-10\">{getCategoryIcon(service.category)}</span>\n </div>\n )}\n <span className=\"absolute left-3 top-3 inline-flex items-center gap-1 rounded-full bg-bg-surface/90 px-2 py-0.5 text-xs font-medium capitalize text-text-secondary shadow-elevation-1 backdrop-blur\">\n {getCategoryIcon(service.category)}\n {service.category.replace(/_/g, ' ')}\n </span>\n {service.featured && (\n <span className=\"absolute right-3 top-3 rounded-full bg-status-warning-text px-2 py-0.5 text-xs font-semibold text-text-inverse shadow-elevation-1\">\n Featured\n </span>\n )}\n </div>\n\n <div className=\"flex flex-1 flex-col p-5\">\n {/* Header */}\n <div className=\"mb-2\">\n <h3 className=\"truncate text-sm font-semibold text-text-primary\">{service.name}</h3>\n <p className=\"text-xs text-text-secondary\">{service.providerName}</p>\n </div>\n\n {/* Rating */}\n <div className=\"mb-3 flex items-center gap-2\">\n <RatingStars rating={service.rating} />\n <span className=\"text-xs font-medium text-text-primary\">{service.rating}</span>\n <span className=\"text-xs text-text-secondary\">({service.reviewCount} reviews)</span>\n </div>\n\n {/* Description */}\n <p className=\"mb-3 line-clamp-2 text-xs text-text-secondary\">{service.description}</p>\n\n {/* Price + Response Time */}\n <div className=\"mb-3 flex items-center justify-between text-xs\">\n <span className=\"font-semibold text-text-primary\">{service.priceRange}</span>\n <span className=\"flex items-center gap-1 text-text-secondary\">\n <Clock className=\"h-3 w-3\" />\n {service.responseTime}\n </span>\n </div>\n\n {/* Availability + Verified */}\n <div className=\"mb-4 flex flex-wrap items-center gap-2\">\n {service.verified && (\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-success-bg-subtle px-2 py-0.5 text-xs font-medium text-status-success-text\">\n <CheckCircle className=\"h-3 w-3\" />\n Verified\n </span>\n )}\n <span className=\"inline-flex items-center gap-1 rounded-full bg-status-info-bg-subtle px-2 py-0.5 text-xs text-status-info-text\">\n <MapPin className=\"h-3 w-3\" />\n {service.availableAreas.length} area{service.availableAreas.length !== 1 ? 's' : ''}\n </span>\n </div>\n\n {/* Actions */}\n <div className=\"mt-auto flex items-center gap-2\">\n <button\n onClick={() => navigate(`../marketplace/${service.id}`)}\n className=\"flex-1 rounded-md bg-action-primary-bg px-3 py-2 text-xs font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n <Phone className=\"mr-1 inline h-3 w-3\" />\n Contact\n </button>\n <button\n aria-label={`Message ${service.providerName}`}\n onClick={() => navigate(`../marketplace/${service.id}`)}\n className=\"rounded-md border border-border-subtle px-3 py-2 text-xs font-medium text-text-primary transition-colors hover:bg-bg-sunken\"\n >\n <MessageCircle className=\"h-3 w-3\" />\n </button>\n </div>\n </div>\n </div>\n );\n}\n\nexport function MarketplacePage() {\n useTrackPageView('housingvista.marketplace.viewed');\n const [search, setSearch] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [activeCategory, setActiveCategory] = useState<string>('all');\n const pagination = useServerPagination(PAGE_SIZE);\n const { setPage } = pagination;\n\n // Debounce the search box so we don't refetch on every keystroke.\n useEffect(() => {\n const timer = setTimeout(() => setDebouncedSearch(search), 300);\n return () => clearTimeout(timer);\n }, [search]);\n\n // Server-side filter — category + search are resolved by the subgraph.\n const serverFilter = useMemo<MarketplaceServiceFilterInput | undefined>(() => {\n const filter: MarketplaceServiceFilterInput = {};\n if (debouncedSearch.trim()) filter.search = debouncedSearch.trim();\n if (activeCategory !== 'all') filter.category = activeCategory;\n return Object.keys(filter).length > 0 ? filter : undefined;\n }, [debouncedSearch, activeCategory]);\n\n // Reset to the first page whenever the server-side filter changes.\n useEffect(() => {\n setPage(1);\n }, [serverFilter, setPage]);\n\n const { data: services, loading } = useMarketplaceServices({\n filter: serverFilter,\n pagination: pagination.pagination,\n });\n\n const hasNextPage = services.length >= pagination.pageSize;\n\n return (\n <PageLayout\n title=\"Service Marketplace\"\n description=\"Find trusted service providers for your property needs\"\n purpose=\"Hire vetted professionals — plumbers, electricians, cleaners, painters, security, and landscapers — to keep your properties in top shape. Browse by category, compare ratings and response times, then contact or message a provider directly.\"\n >\n {/* Category Tabs — primary control zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"flex flex-wrap items-center gap-2 p-3\">\n {categories.map((cat) => (\n <button\n key={cat.value}\n onClick={() => setActiveCategory(cat.value)}\n className={cn(\n 'rounded-full px-4 py-1.5 text-sm font-medium transition-colors',\n activeCategory === cat.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle bg-bg-surface text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n )}\n >\n {cat.label}\n </button>\n ))}\n </EmphasisPanel>\n\n {/* Search */}\n <FilterBar searchValue={search} onSearchChange={setSearch} searchPlaceholder=\"Search services, providers...\" />\n\n <NextSteps\n storageKey=\"housingvista-marketplace\"\n steps={[\n {\n id: 'book-repair',\n label: 'Fix something now',\n description: 'Find a plumber or repair pro for an urgent issue.',\n onClick: () => setActiveCategory('repair'),\n },\n {\n id: 'book-cleaning',\n label: 'Schedule a cleaning',\n description: 'Get a property move-in or turnover ready.',\n onClick: () => setActiveCategory('cleaning'),\n },\n {\n id: 'see-featured',\n label: 'Browse all providers',\n description: 'Clear filters to compare every vetted professional.',\n onClick: () => {\n setActiveCategory('all');\n setSearch('');\n },\n },\n ]}\n />\n\n {/* Results Count */}\n <p className=\"text-sm text-text-secondary\">\n {services.length} service{services.length !== 1 ? 's' : ''} shown\n {pagination.page > 1 ? ` · page ${pagination.page}` : ''}\n </p>\n\n {/* Service Grid */}\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : services.length > 0 ? (\n <>\n <div className=\"grid gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {services.map((service) => (\n <ServiceCard key={service.id} service={service} />\n ))}\n </div>\n <Pagination\n page={pagination.page}\n pageSize={pagination.pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={pagination.page > 1}\n onPageChange={pagination.setPage}\n onPageSizeChange={pagination.setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n title=\"No services found\"\n description=\"Try adjusting your search or category filter to find what you need.\"\n />\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/marketplace/ServiceDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA2EH,wBAAgB,iBAAiB,gCA0NhC"}
1
+ {"version":3,"file":"ServiceDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/marketplace/ServiceDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AA4EH,wBAAgB,iBAAiB,gCA4NhC"}