@burdenoff/microfe-housingvista 2026.930.1 → 2026.930.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.
@@ -1 +1 @@
1
- {"version":3,"file":"ShortlistPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/shortlist/ShortlistPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,eAAO,MAAM,aAAa,mCA+LzB,CAAC"}
1
+ {"version":3,"file":"ShortlistPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/shortlist/ShortlistPage.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAiBH,eAAO,MAAM,aAAa,mCAgMzB,CAAC"}
@@ -157,6 +157,7 @@ var C = 9, w = 3, T = () => {
157
157
  isShortlisted: !0,
158
158
  onToggleShortlist: () => U(e.id),
159
159
  reraStatus: e.reraVerificationStatus,
160
+ verificationStatus: e.verificationStatus,
160
161
  onToggleCompare: I ? () => B(e.id) : void 0,
161
162
  isCompareSelected: R.has(e.id)
162
163
  }, e.id))
@@ -1 +1 @@
1
- {"version":3,"file":"ShortlistPage.js","names":[],"sources":["../../../../src/housingvista/pages/shortlist/ShortlistPage.tsx"],"sourcesContent":["/**\n * HousingVista Shortlist Page\n * The properties the user has saved (housingvistaShortlists), with one-tap\n * un-save and a jump into each property's detail. No mock data.\n * @module housingvista\n */\n\nimport { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Heart, Search, GitCompare } from 'lucide-react';\nimport { Pagination, Button, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, PropertyCard, EmptyState, LoadingSkeleton } from '../../components';\nimport { useShortlists, useRemoveShortlist } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\nimport { cn, formatCompactCurrency } from '../../utils/helpers';\nimport type { Property } from '../../types';\n\nconst PAGE_SIZE = 9;\nconst MAX_COMPARE = 3;\n\nexport const ShortlistPage = () => {\n useTrackPageView('housingvista.shortlist.viewed');\n const navigate = useNavigate();\n const { page, pageSize, pagination, setPage, setPageSize } = useServerPagination(PAGE_SIZE);\n const { data: shortlists, loading } = useShortlists({ limit: pagination.limit, offset: pagination.offset });\n const { removeShortlist } = useRemoveShortlist();\n\n const properties = useMemo(() => shortlists.map((s) => s.property), [shortlists]);\n const hasNextPage = shortlists.length >= pageSize;\n\n // Side-by-side comparison mode (BOFF-3931) — client-side, up to 3 of the\n // currently-loaded shortlist page.\n const [isComparing, setIsComparing] = useState(false);\n const [selectedForCompare, setSelectedForCompare] = useState<Set<string>>(new Set());\n\n const toggleCompare = (id: string) => {\n setSelectedForCompare((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else if (next.size < MAX_COMPARE) {\n next.add(id);\n }\n return next;\n });\n };\n\n const comparedProperties = useMemo(\n () => properties.filter((p) => selectedForCompare.has(p.id)),\n [properties, selectedForCompare]\n );\n\n const comparisonRows: { label: string; render: (p: Property) => string }[] = [\n { label: 'Price', render: (p) => formatCompactCurrency(p.price.amount, p.price.currency) },\n { label: 'Type', render: (p) => p.category },\n { label: 'Status', render: (p) => p.status.replace('_', ' ') },\n { label: 'Bedrooms', render: (p) => String(p.specifications.bedrooms ?? '—') },\n { label: 'Bathrooms', render: (p) => String(p.specifications.bathrooms ?? '—') },\n { label: 'Total area', render: (p) => `${p.specifications.totalArea.toLocaleString()} sq ft` },\n { label: 'Location', render: (p) => [p.location.neighborhood, p.location.city].filter(Boolean).join(', ') },\n { label: 'Amenities', render: (p) => `${p.amenities.filter((a) => a.available).length} available` },\n {\n label: 'RERA status',\n render: (p) => (p.reraVerificationStatus === 'not_applicable' ? 'N/A' : p.reraVerificationStatus),\n },\n ];\n\n const handleRemove = async (propertyId: string) => {\n try {\n await removeShortlist(propertyId);\n notify.success('Removed from shortlist');\n } catch (err) {\n notify.error('Could not update shortlist', (err as Error).message);\n }\n };\n\n const savedLabel = properties.length === 1 ? '1 saved' : `${properties.length} saved`;\n\n return (\n <PageLayout\n title=\"Shortlist\"\n description=\"Properties you've saved to compare and revisit\"\n purpose=\"Everything you've hearted in one place. Compare your saved properties side by side, jump back into any listing to schedule a viewing or make an offer, and remove the ones you've ruled out.\"\n actions={\n <div className=\"flex items-center gap-3\">\n {!loading && properties.length > 0 && (\n <span className=\"hidden rounded-full bg-status-success-bg-subtle px-3 py-1 text-sm font-semibold text-status-success-text sm:inline\">\n {savedLabel}\n </span>\n )}\n {!loading && properties.length > 1 && (\n <button\n onClick={() => {\n setIsComparing((prev) => !prev);\n if (isComparing) setSelectedForCompare(new Set());\n }}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors',\n isComparing\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle text-text-primary hover:bg-bg-sunken'\n )}\n >\n <GitCompare className=\"h-3.5 w-3.5\" />\n {isComparing ? `Comparing (${selectedForCompare.size})` : 'Compare'}\n </button>\n )}\n <Button variant=\"outline\" onClick={() => navigate('../properties')} className=\"gap-2\">\n <Search className=\"h-4 w-4\" />\n Browse Properties\n </Button>\n </div>\n }\n >\n {isComparing && comparedProperties.length >= 2 && (\n <EmphasisPanel className=\"p-4\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Comparison</h3>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"border-b border-border-subtle\">\n <th className=\"pb-2 pr-4 text-left text-text-secondary\">Attribute</th>\n {comparedProperties.map((p) => (\n <th key={p.id} className=\"pb-2 pr-4 text-left font-semibold text-text-primary\">\n {p.title}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {comparisonRows.map((row) => (\n <tr key={row.label}>\n <td className=\"py-2 pr-4 text-text-secondary\">{row.label}</td>\n {comparedProperties.map((p) => (\n <td key={p.id} className=\"py-2 pr-4 font-medium text-text-primary\">\n {row.render(p)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </EmphasisPanel>\n )}\n {isComparing && comparedProperties.length < 2 && (\n <p className=\"text-sm text-text-secondary\">\n Select up to {MAX_COMPARE} properties below to compare them side by side.\n </p>\n )}\n\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : properties.length > 0 ? (\n <>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {properties.map((property) => (\n <PropertyCard\n key={property.id}\n id={property.id}\n title={property.title}\n price={property.price.amount}\n priceType={property.price.type === 'rent' ? 'rent' : 'sale'}\n pricePeriod={property.price.period}\n currency={property.price.currency}\n location={[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n bedrooms={property.specifications.bedrooms}\n bathrooms={property.specifications.bathrooms}\n area={property.specifications.totalArea}\n imageUrl={property.images[0]?.url}\n status={property.status.replace('_', ' ')}\n type={property.category}\n onClick={() => navigate(`../properties/${property.id}`)}\n isShortlisted\n onToggleShortlist={() => handleRemove(property.id)}\n reraStatus={property.reraVerificationStatus}\n onToggleCompare={isComparing ? () => toggleCompare(property.id) : undefined}\n isCompareSelected={selectedForCompare.has(property.id)}\n />\n ))}\n </div>\n\n {/* Pagination (server-side): working prev/next + page-size */}\n <Pagination\n page={page}\n pageSize={pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={page > 1}\n loading={loading}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Heart className=\"h-12 w-12\" />}\n title=\"No saved properties yet\"\n description=\"Tap the heart on any property to save it here for easy comparison later.\"\n action={\n <button\n onClick={() => navigate('../properties')}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n Browse Properties\n </button>\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"ShortlistPage.js","names":[],"sources":["../../../../src/housingvista/pages/shortlist/ShortlistPage.tsx"],"sourcesContent":["/**\n * HousingVista Shortlist Page\n * The properties the user has saved (housingvistaShortlists), with one-tap\n * un-save and a jump into each property's detail. No mock data.\n * @module housingvista\n */\n\nimport { useMemo, useState } from 'react';\nimport { useNavigate } from 'react-router';\nimport { Heart, Search, GitCompare } from 'lucide-react';\nimport { Pagination, Button, EmphasisPanel } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, PropertyCard, EmptyState, LoadingSkeleton } from '../../components';\nimport { useShortlists, useRemoveShortlist } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\nimport { cn, formatCompactCurrency } from '../../utils/helpers';\nimport type { Property } from '../../types';\n\nconst PAGE_SIZE = 9;\nconst MAX_COMPARE = 3;\n\nexport const ShortlistPage = () => {\n useTrackPageView('housingvista.shortlist.viewed');\n const navigate = useNavigate();\n const { page, pageSize, pagination, setPage, setPageSize } = useServerPagination(PAGE_SIZE);\n const { data: shortlists, loading } = useShortlists({ limit: pagination.limit, offset: pagination.offset });\n const { removeShortlist } = useRemoveShortlist();\n\n const properties = useMemo(() => shortlists.map((s) => s.property), [shortlists]);\n const hasNextPage = shortlists.length >= pageSize;\n\n // Side-by-side comparison mode (BOFF-3931) — client-side, up to 3 of the\n // currently-loaded shortlist page.\n const [isComparing, setIsComparing] = useState(false);\n const [selectedForCompare, setSelectedForCompare] = useState<Set<string>>(new Set());\n\n const toggleCompare = (id: string) => {\n setSelectedForCompare((prev) => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else if (next.size < MAX_COMPARE) {\n next.add(id);\n }\n return next;\n });\n };\n\n const comparedProperties = useMemo(\n () => properties.filter((p) => selectedForCompare.has(p.id)),\n [properties, selectedForCompare]\n );\n\n const comparisonRows: { label: string; render: (p: Property) => string }[] = [\n { label: 'Price', render: (p) => formatCompactCurrency(p.price.amount, p.price.currency) },\n { label: 'Type', render: (p) => p.category },\n { label: 'Status', render: (p) => p.status.replace('_', ' ') },\n { label: 'Bedrooms', render: (p) => String(p.specifications.bedrooms ?? '—') },\n { label: 'Bathrooms', render: (p) => String(p.specifications.bathrooms ?? '—') },\n { label: 'Total area', render: (p) => `${p.specifications.totalArea.toLocaleString()} sq ft` },\n { label: 'Location', render: (p) => [p.location.neighborhood, p.location.city].filter(Boolean).join(', ') },\n { label: 'Amenities', render: (p) => `${p.amenities.filter((a) => a.available).length} available` },\n {\n label: 'RERA status',\n render: (p) => (p.reraVerificationStatus === 'not_applicable' ? 'N/A' : p.reraVerificationStatus),\n },\n ];\n\n const handleRemove = async (propertyId: string) => {\n try {\n await removeShortlist(propertyId);\n notify.success('Removed from shortlist');\n } catch (err) {\n notify.error('Could not update shortlist', (err as Error).message);\n }\n };\n\n const savedLabel = properties.length === 1 ? '1 saved' : `${properties.length} saved`;\n\n return (\n <PageLayout\n title=\"Shortlist\"\n description=\"Properties you've saved to compare and revisit\"\n purpose=\"Everything you've hearted in one place. Compare your saved properties side by side, jump back into any listing to schedule a viewing or make an offer, and remove the ones you've ruled out.\"\n actions={\n <div className=\"flex items-center gap-3\">\n {!loading && properties.length > 0 && (\n <span className=\"hidden rounded-full bg-status-success-bg-subtle px-3 py-1 text-sm font-semibold text-status-success-text sm:inline\">\n {savedLabel}\n </span>\n )}\n {!loading && properties.length > 1 && (\n <button\n onClick={() => {\n setIsComparing((prev) => !prev);\n if (isComparing) setSelectedForCompare(new Set());\n }}\n className={cn(\n 'inline-flex items-center gap-1.5 rounded-md px-3 py-1.5 text-xs font-medium transition-colors',\n isComparing\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'border border-border-subtle text-text-primary hover:bg-bg-sunken'\n )}\n >\n <GitCompare className=\"h-3.5 w-3.5\" />\n {isComparing ? `Comparing (${selectedForCompare.size})` : 'Compare'}\n </button>\n )}\n <Button variant=\"outline\" onClick={() => navigate('../properties')} className=\"gap-2\">\n <Search className=\"h-4 w-4\" />\n Browse Properties\n </Button>\n </div>\n }\n >\n {isComparing && comparedProperties.length >= 2 && (\n <EmphasisPanel className=\"p-4\">\n <h3 className=\"mb-3 text-sm font-semibold text-text-primary\">Comparison</h3>\n <div className=\"overflow-x-auto\">\n <table className=\"w-full text-xs\">\n <thead>\n <tr className=\"border-b border-border-subtle\">\n <th className=\"pb-2 pr-4 text-left text-text-secondary\">Attribute</th>\n {comparedProperties.map((p) => (\n <th key={p.id} className=\"pb-2 pr-4 text-left font-semibold text-text-primary\">\n {p.title}\n </th>\n ))}\n </tr>\n </thead>\n <tbody className=\"divide-y divide-border\">\n {comparisonRows.map((row) => (\n <tr key={row.label}>\n <td className=\"py-2 pr-4 text-text-secondary\">{row.label}</td>\n {comparedProperties.map((p) => (\n <td key={p.id} className=\"py-2 pr-4 font-medium text-text-primary\">\n {row.render(p)}\n </td>\n ))}\n </tr>\n ))}\n </tbody>\n </table>\n </div>\n </EmphasisPanel>\n )}\n {isComparing && comparedProperties.length < 2 && (\n <p className=\"text-sm text-text-secondary\">\n Select up to {MAX_COMPARE} properties below to compare them side by side.\n </p>\n )}\n\n {loading ? (\n <LoadingSkeleton variant=\"card\" count={6} />\n ) : properties.length > 0 ? (\n <>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2 lg:grid-cols-3\">\n {properties.map((property) => (\n <PropertyCard\n key={property.id}\n id={property.id}\n title={property.title}\n price={property.price.amount}\n priceType={property.price.type === 'rent' ? 'rent' : 'sale'}\n pricePeriod={property.price.period}\n currency={property.price.currency}\n location={[property.location.neighborhood, property.location.city].filter(Boolean).join(', ')}\n bedrooms={property.specifications.bedrooms}\n bathrooms={property.specifications.bathrooms}\n area={property.specifications.totalArea}\n imageUrl={property.images[0]?.url}\n status={property.status.replace('_', ' ')}\n type={property.category}\n onClick={() => navigate(`../properties/${property.id}`)}\n isShortlisted\n onToggleShortlist={() => handleRemove(property.id)}\n reraStatus={property.reraVerificationStatus}\n verificationStatus={property.verificationStatus}\n onToggleCompare={isComparing ? () => toggleCompare(property.id) : undefined}\n isCompareSelected={selectedForCompare.has(property.id)}\n />\n ))}\n </div>\n\n {/* Pagination (server-side): working prev/next + page-size */}\n <Pagination\n page={page}\n pageSize={pageSize}\n hasNextPage={hasNextPage}\n hasPreviousPage={page > 1}\n loading={loading}\n onPageChange={setPage}\n onPageSizeChange={setPageSize}\n />\n </>\n ) : (\n <EmptyState\n illustration=\"empty-generic\"\n icon={<Heart className=\"h-12 w-12\" />}\n title=\"No saved properties yet\"\n description=\"Tap the heart on any property to save it here for easy comparison later.\"\n action={\n <button\n onClick={() => navigate('../properties')}\n className=\"rounded-md bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg-hover\"\n >\n Browse Properties\n </button>\n }\n />\n )}\n </PageLayout>\n );\n};\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-housingvista",
3
- "version": "2026.930.1",
3
+ "version": "2026.930.2",
4
4
  "description": "Burdenoff HousingVista Microfrontend - Comprehensive real estate platform for property management, investment, and transactions",
5
5
  "type": "module",
6
6
  "files": [