@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":"ChatPage.js","names":[],"sources":["../../../../src/housingvista/pages/chat/ChatPage.tsx"],"sourcesContent":["/**\n * Messages — the real HousingVista inbox. A two-pane conversations UI (thread\n * list + chat thread with bubbles) backed by wspace-conversations-svc:\n * - `useHousingVistaConversations` lists the user's product threads,\n * - `useConversationMessages` streams the selected thread,\n * - `useSendMessage` posts new messages.\n * Everything is persisted server-side; when there are no threads yet we show a\n * tasteful empty state (never fabricated rows). Fully responsive: on mobile the\n * list and the open thread swap places (back button), on desktop they sit\n * side-by-side.\n * @module housingvista\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { ArrowLeft, MapPin, MessageSquare, Search, Send } from 'lucide-react';\nimport { Button, EmphasisPanel, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, EmptyState, StatCard } from '../../components';\nimport { useHousingVistaConversations, type HvConversationSummary } from '../../hooks/messages';\nimport { useConversationMessages, useSendMessage } from '../../hooks';\nimport { useHousingVista } from '../../context/HousingVistaContext';\nimport { notify } from '../../lib/toast';\nimport { cn, getRelativeTime } from '../../utils/helpers';\n\n/** Deterministic accent for an avatar chip, derived from the thread title. */\nconst AVATAR_ACCENTS = [\n 'bg-status-info-bg-subtle text-status-info-text',\n 'bg-status-success-bg-subtle text-status-success-text',\n 'bg-status-warning-bg-subtle text-status-warning-text',\n 'bg-action-primary-bg/15 text-primary',\n];\n\nfunction initials(title: string): string {\n const parts = title.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return '?';\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n}\n\nfunction accentFor(id: string): string {\n let sum = 0;\n for (let i = 0; i < id.length; i += 1) sum += id.charCodeAt(i);\n return AVATAR_ACCENTS[sum % AVATAR_ACCENTS.length];\n}\n\nfunction messageTime(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return '';\n return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });\n}\n\nfunction Avatar({ title, id, size = 'md' }: { title: string; id: string; size?: 'sm' | 'md' }) {\n return (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center justify-center rounded-full font-semibold',\n size === 'md' ? 'h-10 w-10 text-sm' : 'h-9 w-9 text-xs',\n accentFor(id)\n )}\n aria-hidden\n >\n {initials(title)}\n </span>\n );\n}\n\nexport function ChatPage() {\n const navigate = useNavigate();\n const { currentUser } = useHousingVista();\n const currentUserId = currentUser?.id ?? '';\n\n const { data: conversations, loading, refetch } = useHousingVistaConversations();\n const { sendMessage, loading: sending } = useSendMessage();\n\n const [selectedId, setSelectedId] = useState<string | undefined>();\n const [query, setQuery] = useState('');\n const [draft, setDraft] = useState('');\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Default-select the first thread on desktop once data lands.\n useEffect(() => {\n if (!selectedId && conversations.length > 0 && typeof window !== 'undefined' && window.innerWidth >= 1024) {\n setSelectedId(conversations[0].id);\n }\n }, [conversations, selectedId]);\n\n const selected: HvConversationSummary | undefined = useMemo(\n () => conversations.find((c) => c.id === selectedId),\n [conversations, selectedId]\n );\n\n const { data: messages, loading: loadingMessages } = useConversationMessages(selectedId);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages, selectedId]);\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return conversations;\n return conversations.filter(\n (c) => c.title.toLowerCase().includes(q) || c.lastMessageText.toLowerCase().includes(q)\n );\n }, [conversations, query]);\n\n const unreadThreads = conversations.filter((c) => c.unreadCount > 0).length;\n\n const handleSend = async () => {\n const text = draft.trim();\n if (!text || !selectedId) return;\n try {\n await sendMessage(selectedId, text);\n setDraft('');\n void refetch();\n } catch (err) {\n notify.error('Message not sent', (err as Error).message);\n }\n };\n\n const emptyInbox = !loading && conversations.length === 0;\n\n return (\n <PageLayout\n title=\"Messages\"\n description=\"Your conversations with property owners, agents, and service providers\"\n purpose=\"Every thread you start from a property, listing, or service lands here — read the full history, pick up where you left off, and reply. Messages are delivered to the other party's inbox in real time.\"\n >\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <StatCard label=\"Conversations\" value={conversations.length} icon={<MessageSquare className=\"h-4 w-4\" />} />\n <StatCard label=\"Unread threads\" value={unreadThreads} icon={<MessageSquare className=\"h-4 w-4\" />} />\n <StatCard\n label=\"With updates today\"\n value={conversations.filter((c) => c.lastMessageAt && getRelativeTime(c.lastMessageAt) === 'Today').length}\n icon={<Send className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n {emptyInbox ? (\n <EmptyState\n illustration=\"empty-generic\"\n icon={<MessageSquare className=\"h-12 w-12\" />}\n title=\"No messages yet\"\n description=\"Start a conversation from any property or service — reach out to an owner or provider and your thread will show up here.\"\n action={<Button onClick={() => navigate('../properties')}>Browse properties</Button>}\n />\n ) : (\n <GlassCard treatment=\"plain\" className=\"overflow-hidden p-0\">\n <div className=\"grid h-[68vh] min-h-[26rem] grid-cols-1 lg:grid-cols-[20rem_1fr]\">\n {/* Thread list */}\n <aside\n className={cn('flex flex-col border-border-subtle lg:border-r', selectedId ? 'hidden lg:flex' : 'flex')}\n >\n <div className=\"border-b border-border-subtle p-3\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search conversations\"\n aria-label=\"Search conversations\"\n className=\"h-10 w-full rounded-md border border-border-subtle bg-bg-surface pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n {loading && conversations.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-text-secondary\">Loading conversations…</p>\n ) : filtered.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-text-secondary\">No conversations match your search.</p>\n ) : (\n <ul>\n {filtered.map((conversation) => {\n const active = conversation.id === selectedId;\n return (\n <li key={conversation.id}>\n <button\n type=\"button\"\n onClick={() => {\n setSelectedId(conversation.id);\n setDraft('');\n }}\n className={cn(\n 'flex w-full items-start gap-3 border-b border-border-subtle px-3 py-3 text-left transition-colors',\n active ? 'bg-action-primary-bg/10' : 'hover:bg-bg-sunken'\n )}\n >\n <Avatar title={conversation.title} id={conversation.id} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {conversation.title}\n </span>\n {conversation.lastMessageAt && (\n <span className=\"shrink-0 text-xs text-text-secondary\">\n {getRelativeTime(conversation.lastMessageAt)}\n </span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-2\">\n <span className=\"min-w-0 flex-1 truncate text-xs text-text-secondary\">\n {conversation.lastMessageText || 'No messages yet'}\n </span>\n {conversation.unreadCount > 0 && (\n <span className=\"inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-action-primary-bg px-1.5 text-[0.65rem] font-semibold text-action-primary-text\">\n {conversation.unreadCount}\n </span>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </aside>\n\n {/* Thread */}\n <section className={cn('flex min-h-0 flex-col', selectedId ? 'flex' : 'hidden lg:flex')}>\n {selected ? (\n <>\n <header className=\"flex items-center gap-3 border-b border-border-subtle p-3\">\n <button\n type=\"button\"\n onClick={() => setSelectedId(undefined)}\n className=\"rounded-md p-1.5 text-text-secondary transition-colors hover:bg-bg-sunken lg:hidden\"\n aria-label=\"Back to conversations\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <Avatar title={selected.title} id={selected.id} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-sm font-semibold text-text-primary\">{selected.title}</h2>\n {selected.contextHref && (\n <button\n type=\"button\"\n onClick={() => navigate(`..${selected.contextHref}`)}\n className=\"flex items-center gap-1 text-xs text-text-secondary transition-colors hover:text-primary\"\n >\n <MapPin className=\"h-3 w-3\" />\n View listing\n </button>\n )}\n </div>\n </header>\n\n <div ref={scrollRef} className=\"min-h-0 flex-1 space-y-2 overflow-y-auto bg-bg-sunken/40 p-4\">\n {loadingMessages && messages.length === 0 ? (\n <p className=\"py-10 text-center text-sm text-text-secondary\">Loading messages…</p>\n ) : messages.length === 0 ? (\n <p className=\"py-10 text-center text-sm text-text-secondary\">\n No messages yet. Say hello to get the conversation started.\n </p>\n ) : (\n messages.map((message) => {\n const mine = message.authorId === currentUserId;\n return (\n <div key={message.id} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>\n <div className={cn('max-w-[78%]', mine ? 'items-end' : 'items-start')}>\n <div\n className={cn(\n 'rounded-2xl px-3.5 py-2 text-sm',\n mine\n ? 'rounded-br-sm bg-action-primary-bg text-action-primary-text'\n : 'rounded-bl-sm border border-border-subtle bg-bg-surface text-text-primary'\n )}\n >\n {message.text}\n </div>\n <div className={cn('mt-1 px-1 text-[0.65rem] text-text-secondary', mine && 'text-right')}>\n {messageTime(message.createdAt)}\n </div>\n </div>\n </div>\n );\n })\n )}\n </div>\n\n <div className=\"flex items-end gap-2 border-t border-border-subtle p-3\">\n <textarea\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n void handleSend();\n }\n }}\n rows={1}\n placeholder=\"Type a message…\"\n aria-label=\"Message\"\n className=\"max-h-32 min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <Button type=\"button\" onClick={handleSend} disabled={!draft.trim() || sending}>\n <Send className=\"h-4 w-4\" />\n <span className=\"ml-1 hidden sm:inline\">Send</span>\n </Button>\n </div>\n </>\n ) : (\n <div className=\"hidden flex-1 items-center justify-center p-8 lg:flex\">\n <div className=\"text-center\">\n <MessageSquare className=\"mx-auto h-10 w-10 text-text-secondary\" />\n <p className=\"mt-3 text-sm text-text-secondary\">Select a conversation to read and reply.</p>\n </div>\n </div>\n )}\n </section>\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"ChatPage.js","names":[],"sources":["../../../../src/housingvista/pages/chat/ChatPage.tsx"],"sourcesContent":["/**\n * Messages — the real HousingVista inbox. A two-pane conversations UI (thread\n * list + chat thread with bubbles) backed by wspace-conversations-svc:\n * - `useHousingVistaConversations` lists the user's product threads,\n * - `useConversationMessages` streams the selected thread,\n * - `useSendMessage` posts new messages.\n * Everything is persisted server-side; when there are no threads yet we show a\n * tasteful empty state (never fabricated rows). Fully responsive: on mobile the\n * list and the open thread swap places (back button), on desktop they sit\n * side-by-side.\n * @module housingvista\n */\n\nimport { useEffect, useMemo, useRef, useState } from 'react';\nimport { useNavigate } from 'react-router-dom';\nimport { ArrowLeft, MapPin, MessageSquare, Search, Send } from 'lucide-react';\nimport { Button, EmphasisPanel, GlassCard } from '@burdenoff/fe-libs/ui';\nimport { PageLayout, EmptyState, StatCard } from '../../components';\nimport { useHousingVistaConversations, type HvConversationSummary } from '../../hooks/messages';\nimport { useConversationMessages, useSendMessage } from '../../hooks';\nimport { useHousingVista } from '../../context/HousingVistaContext';\nimport { notify } from '../../lib/toast';\nimport { cn, getRelativeTime } from '../../utils/helpers';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\n/** Deterministic accent for an avatar chip, derived from the thread title. */\nconst AVATAR_ACCENTS = [\n 'bg-status-info-bg-subtle text-status-info-text',\n 'bg-status-success-bg-subtle text-status-success-text',\n 'bg-status-warning-bg-subtle text-status-warning-text',\n 'bg-action-primary-bg/15 text-primary',\n];\n\nfunction initials(title: string): string {\n const parts = title.trim().split(/\\s+/).filter(Boolean);\n if (parts.length === 0) return '?';\n if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();\n return (parts[0][0] + parts[parts.length - 1][0]).toUpperCase();\n}\n\nfunction accentFor(id: string): string {\n let sum = 0;\n for (let i = 0; i < id.length; i += 1) sum += id.charCodeAt(i);\n return AVATAR_ACCENTS[sum % AVATAR_ACCENTS.length];\n}\n\nfunction messageTime(iso: string): string {\n const date = new Date(iso);\n if (Number.isNaN(date.getTime())) return '';\n return date.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });\n}\n\nfunction Avatar({ title, id, size = 'md' }: { title: string; id: string; size?: 'sm' | 'md' }) {\n return (\n <span\n className={cn(\n 'inline-flex shrink-0 items-center justify-center rounded-full font-semibold',\n size === 'md' ? 'h-10 w-10 text-sm' : 'h-9 w-9 text-xs',\n accentFor(id)\n )}\n aria-hidden\n >\n {initials(title)}\n </span>\n );\n}\n\nexport function ChatPage() {\n useTrackPageView('housingvista.chat.viewed');\n const navigate = useNavigate();\n const { currentUser } = useHousingVista();\n const currentUserId = currentUser?.id ?? '';\n\n const { data: conversations, loading, refetch } = useHousingVistaConversations();\n const { sendMessage, loading: sending } = useSendMessage();\n\n const [selectedId, setSelectedId] = useState<string | undefined>();\n const [query, setQuery] = useState('');\n const [draft, setDraft] = useState('');\n const scrollRef = useRef<HTMLDivElement>(null);\n\n // Default-select the first thread on desktop once data lands.\n useEffect(() => {\n if (!selectedId && conversations.length > 0 && typeof window !== 'undefined' && window.innerWidth >= 1024) {\n setSelectedId(conversations[0].id);\n }\n }, [conversations, selectedId]);\n\n const selected: HvConversationSummary | undefined = useMemo(\n () => conversations.find((c) => c.id === selectedId),\n [conversations, selectedId]\n );\n\n const { data: messages, loading: loadingMessages } = useConversationMessages(selectedId);\n\n useEffect(() => {\n scrollRef.current?.scrollTo({ top: scrollRef.current.scrollHeight });\n }, [messages, selectedId]);\n\n const filtered = useMemo(() => {\n const q = query.trim().toLowerCase();\n if (!q) return conversations;\n return conversations.filter(\n (c) => c.title.toLowerCase().includes(q) || c.lastMessageText.toLowerCase().includes(q)\n );\n }, [conversations, query]);\n\n const unreadThreads = conversations.filter((c) => c.unreadCount > 0).length;\n\n const handleSend = async () => {\n const text = draft.trim();\n if (!text || !selectedId) return;\n try {\n await sendMessage(selectedId, text);\n setDraft('');\n void refetch();\n } catch (err) {\n notify.error('Message not sent', (err as Error).message);\n }\n };\n\n const emptyInbox = !loading && conversations.length === 0;\n\n return (\n <PageLayout\n title=\"Messages\"\n description=\"Your conversations with property owners, agents, and service providers\"\n purpose=\"Every thread you start from a property, listing, or service lands here — read the full history, pick up where you left off, and reply. Messages are delivered to the other party's inbox in real time.\"\n >\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 sm:grid-cols-3\">\n <StatCard label=\"Conversations\" value={conversations.length} icon={<MessageSquare className=\"h-4 w-4\" />} />\n <StatCard label=\"Unread threads\" value={unreadThreads} icon={<MessageSquare className=\"h-4 w-4\" />} />\n <StatCard\n label=\"With updates today\"\n value={conversations.filter((c) => c.lastMessageAt && getRelativeTime(c.lastMessageAt) === 'Today').length}\n icon={<Send className=\"h-4 w-4\" />}\n />\n </div>\n </EmphasisPanel>\n\n {emptyInbox ? (\n <EmptyState\n illustration=\"empty-generic\"\n icon={<MessageSquare className=\"h-12 w-12\" />}\n title=\"No messages yet\"\n description=\"Start a conversation from any property or service — reach out to an owner or provider and your thread will show up here.\"\n action={<Button onClick={() => navigate('../properties')}>Browse properties</Button>}\n />\n ) : (\n <GlassCard treatment=\"plain\" className=\"overflow-hidden p-0\">\n <div className=\"grid h-[68vh] min-h-[26rem] grid-cols-1 lg:grid-cols-[20rem_1fr]\">\n {/* Thread list */}\n <aside\n className={cn('flex flex-col border-border-subtle lg:border-r', selectedId ? 'hidden lg:flex' : 'flex')}\n >\n <div className=\"border-b border-border-subtle p-3\">\n <div className=\"relative\">\n <Search className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-text-secondary\" />\n <input\n type=\"search\"\n value={query}\n onChange={(event) => setQuery(event.target.value)}\n placeholder=\"Search conversations\"\n aria-label=\"Search conversations\"\n className=\"h-10 w-full rounded-md border border-border-subtle bg-bg-surface pl-9 pr-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n </div>\n </div>\n <div className=\"min-h-0 flex-1 overflow-y-auto\">\n {loading && conversations.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-text-secondary\">Loading conversations…</p>\n ) : filtered.length === 0 ? (\n <p className=\"p-6 text-center text-sm text-text-secondary\">No conversations match your search.</p>\n ) : (\n <ul>\n {filtered.map((conversation) => {\n const active = conversation.id === selectedId;\n return (\n <li key={conversation.id}>\n <button\n type=\"button\"\n onClick={() => {\n setSelectedId(conversation.id);\n setDraft('');\n }}\n className={cn(\n 'flex w-full items-start gap-3 border-b border-border-subtle px-3 py-3 text-left transition-colors',\n active ? 'bg-action-primary-bg/10' : 'hover:bg-bg-sunken'\n )}\n >\n <Avatar title={conversation.title} id={conversation.id} />\n <div className=\"min-w-0 flex-1\">\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"truncate text-sm font-semibold text-text-primary\">\n {conversation.title}\n </span>\n {conversation.lastMessageAt && (\n <span className=\"shrink-0 text-xs text-text-secondary\">\n {getRelativeTime(conversation.lastMessageAt)}\n </span>\n )}\n </div>\n <div className=\"mt-0.5 flex items-center gap-2\">\n <span className=\"min-w-0 flex-1 truncate text-xs text-text-secondary\">\n {conversation.lastMessageText || 'No messages yet'}\n </span>\n {conversation.unreadCount > 0 && (\n <span className=\"inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-action-primary-bg px-1.5 text-[0.65rem] font-semibold text-action-primary-text\">\n {conversation.unreadCount}\n </span>\n )}\n </div>\n </div>\n </button>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n </aside>\n\n {/* Thread */}\n <section className={cn('flex min-h-0 flex-col', selectedId ? 'flex' : 'hidden lg:flex')}>\n {selected ? (\n <>\n <header className=\"flex items-center gap-3 border-b border-border-subtle p-3\">\n <button\n type=\"button\"\n onClick={() => setSelectedId(undefined)}\n className=\"rounded-md p-1.5 text-text-secondary transition-colors hover:bg-bg-sunken lg:hidden\"\n aria-label=\"Back to conversations\"\n >\n <ArrowLeft className=\"h-5 w-5\" />\n </button>\n <Avatar title={selected.title} id={selected.id} size=\"sm\" />\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"truncate text-sm font-semibold text-text-primary\">{selected.title}</h2>\n {selected.contextHref && (\n <button\n type=\"button\"\n onClick={() => navigate(`..${selected.contextHref}`)}\n className=\"flex items-center gap-1 text-xs text-text-secondary transition-colors hover:text-primary\"\n >\n <MapPin className=\"h-3 w-3\" />\n View listing\n </button>\n )}\n </div>\n </header>\n\n <div ref={scrollRef} className=\"min-h-0 flex-1 space-y-2 overflow-y-auto bg-bg-sunken/40 p-4\">\n {loadingMessages && messages.length === 0 ? (\n <p className=\"py-10 text-center text-sm text-text-secondary\">Loading messages…</p>\n ) : messages.length === 0 ? (\n <p className=\"py-10 text-center text-sm text-text-secondary\">\n No messages yet. Say hello to get the conversation started.\n </p>\n ) : (\n messages.map((message) => {\n const mine = message.authorId === currentUserId;\n return (\n <div key={message.id} className={cn('flex', mine ? 'justify-end' : 'justify-start')}>\n <div className={cn('max-w-[78%]', mine ? 'items-end' : 'items-start')}>\n <div\n className={cn(\n 'rounded-2xl px-3.5 py-2 text-sm',\n mine\n ? 'rounded-br-sm bg-action-primary-bg text-action-primary-text'\n : 'rounded-bl-sm border border-border-subtle bg-bg-surface text-text-primary'\n )}\n >\n {message.text}\n </div>\n <div className={cn('mt-1 px-1 text-[0.65rem] text-text-secondary', mine && 'text-right')}>\n {messageTime(message.createdAt)}\n </div>\n </div>\n </div>\n );\n })\n )}\n </div>\n\n <div className=\"flex items-end gap-2 border-t border-border-subtle p-3\">\n <textarea\n value={draft}\n onChange={(event) => setDraft(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && !event.shiftKey) {\n event.preventDefault();\n void handleSend();\n }\n }}\n rows={1}\n placeholder=\"Type a message…\"\n aria-label=\"Message\"\n className=\"max-h-32 min-h-10 flex-1 resize-none rounded-md border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]\"\n />\n <Button type=\"button\" onClick={handleSend} disabled={!draft.trim() || sending}>\n <Send className=\"h-4 w-4\" />\n <span className=\"ml-1 hidden sm:inline\">Send</span>\n </Button>\n </div>\n </>\n ) : (\n <div className=\"hidden flex-1 items-center justify-center p-8 lg:flex\">\n <div className=\"text-center\">\n <MessageSquare className=\"mx-auto h-10 w-10 text-text-secondary\" />\n <p className=\"mt-3 text-sm text-text-secondary\">Select a conversation to read and reply.</p>\n </div>\n </div>\n )}\n </section>\n </div>\n </GlassCard>\n )}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HomeLoanDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/finance/HomeLoanDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA6CH,wBAAgB,kBAAkB,gCAqQjC"}
1
+ {"version":3,"file":"HomeLoanDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/finance/HomeLoanDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AA8CH,wBAAgB,kBAAkB,gCAuQjC"}
@@ -3,210 +3,213 @@ import { StatusBadge as r } from "../../components/StatusBadge.js";
3
3
  import { EmptyState as i } from "../../components/EmptyState.js";
4
4
  import { Breadcrumbs as a } from "../../components/Breadcrumbs.js";
5
5
  import { LoadingSkeleton as o } from "../../components/LoadingSkeleton.js";
6
- import { useHomeLoanOffer as s } from "../../hooks/index.js";
7
- import { ContactOwnerDialog as c } from "../../components/ContactOwnerDialog.js";
6
+ import { useTrackPageView as s } from "../../hooks/useHousingVistaAnalytics.js";
7
+ import { useHomeLoanOffer as c } from "../../hooks/index.js";
8
+ import { ContactOwnerDialog as l } from "../../components/ContactOwnerDialog.js";
8
9
  import "../../components/index.js";
9
- import { useMemo as l, useState as u } from "react";
10
- import { ArrowLeft as d, Building2 as f, Calculator as p, CalendarClock as m, CheckCircle as h, Gift as g, Percent as _, Star as v, Wallet as y } from "lucide-react";
11
- import { useLocation as b, useNavigate as x, useParams as S } from "react-router-dom";
12
- import { jsx as C, jsxs as w } from "react/jsx-runtime";
13
- import { Button as T, EmphasisPanel as E, GlassCard as D, PagePurpose as O } from "@burdenoff/fe-libs/ui";
10
+ import { useMemo as u, useState as d } from "react";
11
+ import { ArrowLeft as f, Building2 as p, Calculator as m, CalendarClock as h, CheckCircle as g, Gift as _, Percent as v, Star as y, Wallet as b } from "lucide-react";
12
+ import { useLocation as x, useNavigate as S, useParams as C } from "react-router-dom";
13
+ import { jsx as w, jsxs as T } from "react/jsx-runtime";
14
+ import { Button as E, EmphasisPanel as D, GlassCard as O, PagePurpose as k } from "@burdenoff/fe-libs/ui";
14
15
  //#region src/housingvista/pages/finance/HomeLoanDetailPage.tsx
15
- var k = "w-full accent-[var(--color-action-primary-bg)]";
16
- function A(e, t, n) {
16
+ var A = "w-full accent-[var(--color-action-primary-bg)]";
17
+ function j(e, t, n) {
17
18
  if (e <= 0 || t <= 0 || n <= 0) return 0;
18
19
  let r = t / 12 / 100, i = n * 12, a = e * r * (1 + r) ** +i / ((1 + r) ** +i - 1);
19
20
  return Math.round(a);
20
21
  }
21
- function j({ rating: t }) {
22
- return /* @__PURE__ */ C("div", {
22
+ function M({ rating: t }) {
23
+ return /* @__PURE__ */ w("div", {
23
24
  className: "flex items-center gap-0.5 text-status-warning-text",
24
- children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ C(v, { className: e("h-4 w-4", r < Math.floor(t) ? "fill-current" : "fill-none text-text-secondary/30") }, r))
25
+ children: Array.from({ length: 5 }).map((n, r) => /* @__PURE__ */ w(y, { className: e("h-4 w-4", r < Math.floor(t) ? "fill-current" : "fill-none text-text-secondary/30") }, r))
25
26
  });
26
27
  }
27
- function M() {
28
- let { id: v } = S(), M = x(), N = b(), { data: P, loading: F } = s(v), [I, L] = u(5e5), [R, z] = u(20), [B, V] = u(!1), H = P?.interestRate ?? 0, U = l(() => A(I, H, R), [
29
- I,
30
- H,
31
- R
32
- ]), W = U * R * 12, G = W - I;
33
- if (F) return /* @__PURE__ */ C("div", {
28
+ function N() {
29
+ let { id: y } = C();
30
+ s("housingvista.home_loan.viewed", y);
31
+ let N = S(), P = x(), { data: F, loading: I } = c(y), [L, R] = d(5e5), [z, B] = d(20), [V, H] = d(!1), U = F?.interestRate ?? 0, W = u(() => j(L, U, z), [
32
+ L,
33
+ U,
34
+ z
35
+ ]), G = W * z * 12, K = G - L;
36
+ if (I) return /* @__PURE__ */ w("div", {
34
37
  className: "p-6",
35
- children: /* @__PURE__ */ C(o, { variant: "detail" })
38
+ children: /* @__PURE__ */ w(o, { variant: "detail" })
36
39
  });
37
- if (!P) return /* @__PURE__ */ C("div", {
40
+ if (!F) return /* @__PURE__ */ w("div", {
38
41
  className: "p-6",
39
- children: /* @__PURE__ */ C(i, {
42
+ children: /* @__PURE__ */ w(i, {
40
43
  illustration: "empty-data",
41
- icon: /* @__PURE__ */ C(f, { className: "h-12 w-12" }),
44
+ icon: /* @__PURE__ */ w(p, { className: "h-12 w-12" }),
42
45
  title: "Loan Offer Not Found",
43
46
  description: "The loan offer you're looking for doesn't exist or is no longer available.",
44
- action: /* @__PURE__ */ w("button", {
45
- onClick: () => M("../home-loans"),
47
+ action: /* @__PURE__ */ T("button", {
48
+ onClick: () => N("../home-loans"),
46
49
  className: "inline-flex items-center gap-2 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",
47
- children: [/* @__PURE__ */ C(d, { className: "h-4 w-4" }), "Back to Home Loans"]
50
+ children: [/* @__PURE__ */ w(f, { className: "h-4 w-4" }), "Back to Home Loans"]
48
51
  })
49
52
  })
50
53
  });
51
- let K = P.features ?? [];
52
- return /* @__PURE__ */ w("div", {
54
+ let q = F.features ?? [];
55
+ return /* @__PURE__ */ T("div", {
53
56
  className: "flex flex-col gap-6 p-6",
54
57
  children: [
55
- /* @__PURE__ */ C(a, { items: [{
58
+ /* @__PURE__ */ w(a, { items: [{
56
59
  label: "Home Loans",
57
60
  href: "../"
58
- }, { label: P.bankName }] }),
59
- /* @__PURE__ */ w("div", {
61
+ }, { label: F.bankName }] }),
62
+ /* @__PURE__ */ T("div", {
60
63
  className: "flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between",
61
- children: [/* @__PURE__ */ w("div", {
64
+ children: [/* @__PURE__ */ T("div", {
62
65
  className: "flex items-start gap-4",
63
- children: [/* @__PURE__ */ C("div", {
66
+ children: [/* @__PURE__ */ w("div", {
64
67
  className: "flex h-12 w-12 shrink-0 items-center justify-center rounded-lg bg-bg-sunken text-text-secondary",
65
- children: /* @__PURE__ */ C(f, { className: "h-6 w-6" })
66
- }), /* @__PURE__ */ w("div", { children: [
67
- /* @__PURE__ */ w("button", {
68
- onClick: () => M("../home-loans"),
68
+ children: /* @__PURE__ */ w(p, { className: "h-6 w-6" })
69
+ }), /* @__PURE__ */ T("div", { children: [
70
+ /* @__PURE__ */ T("button", {
71
+ onClick: () => N("../home-loans"),
69
72
  className: "mb-2 inline-flex items-center gap-2 rounded-md px-2 py-1 text-sm text-text-secondary transition-colors hover:bg-bg-sunken hover:text-text-primary",
70
- children: [/* @__PURE__ */ C(d, { className: "h-4 w-4" }), "Back to Home Loans"]
73
+ children: [/* @__PURE__ */ w(f, { className: "h-4 w-4" }), "Back to Home Loans"]
71
74
  }),
72
- /* @__PURE__ */ C("h1", {
75
+ /* @__PURE__ */ w("h1", {
73
76
  className: "text-2xl font-semibold text-text-primary",
74
- children: P.bankName
77
+ children: F.bankName
75
78
  }),
76
- /* @__PURE__ */ w("div", {
79
+ /* @__PURE__ */ T("div", {
77
80
  className: "mt-2 flex flex-wrap items-center gap-2",
78
- children: [P.rating != null && /* @__PURE__ */ w("span", {
81
+ children: [F.rating != null && /* @__PURE__ */ T("span", {
79
82
  className: "inline-flex items-center gap-1.5",
80
- children: [/* @__PURE__ */ C(j, { rating: P.rating }), /* @__PURE__ */ C("span", {
83
+ children: [/* @__PURE__ */ w(M, { rating: F.rating }), /* @__PURE__ */ w("span", {
81
84
  className: "text-sm text-text-secondary",
82
- children: P.rating
85
+ children: F.rating
83
86
  })]
84
- }), P.specialOffer && /* @__PURE__ */ C(r, {
87
+ }), F.specialOffer && /* @__PURE__ */ w(r, {
85
88
  label: "Special Offer",
86
89
  variant: "warning"
87
90
  })]
88
91
  })
89
92
  ] })]
90
- }), /* @__PURE__ */ C(T, {
93
+ }), /* @__PURE__ */ w(E, {
91
94
  type: "button",
92
95
  variant: "default",
93
- onClick: () => V(!0),
96
+ onClick: () => H(!0),
94
97
  children: "Apply Now"
95
98
  })]
96
99
  }),
97
- /* @__PURE__ */ w(O, {
100
+ /* @__PURE__ */ T(k, {
98
101
  className: "max-w-3xl",
99
102
  children: [
100
103
  "The full terms of this offer with a live EMI estimate at the bank's headline rate. Model your loan amount and tenure to see the real monthly cost, then apply to connect with ",
101
- P.bankName,
104
+ F.bankName,
102
105
  " through Messages."
103
106
  ]
104
107
  }),
105
- P.specialOffer && /* @__PURE__ */ w("div", {
108
+ F.specialOffer && /* @__PURE__ */ T("div", {
106
109
  className: "flex items-center gap-2 rounded-lg bg-status-warning-bg-subtle p-3 text-sm text-status-warning-text",
107
- children: [/* @__PURE__ */ C(g, { className: "h-4 w-4 shrink-0" }), P.specialOffer]
110
+ children: [/* @__PURE__ */ w(_, { className: "h-4 w-4 shrink-0" }), F.specialOffer]
108
111
  }),
109
- /* @__PURE__ */ w(E, {
112
+ /* @__PURE__ */ T(D, {
110
113
  className: "p-5",
111
- children: [/* @__PURE__ */ w("div", {
114
+ children: [/* @__PURE__ */ T("div", {
112
115
  className: "mb-4 flex items-center gap-2",
113
- children: [/* @__PURE__ */ C(p, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ w("h2", {
116
+ children: [/* @__PURE__ */ w(m, { className: "h-5 w-5 text-text-secondary" }), /* @__PURE__ */ T("h2", {
114
117
  className: "text-lg font-semibold text-text-primary",
115
118
  children: [
116
119
  "EMI Estimate at ",
117
- P.interestRate,
120
+ F.interestRate,
118
121
  "%"
119
122
  ]
120
123
  })]
121
- }), /* @__PURE__ */ w("div", {
124
+ }), /* @__PURE__ */ T("div", {
122
125
  className: "grid gap-6 md:grid-cols-2",
123
- children: [/* @__PURE__ */ w("div", {
126
+ children: [/* @__PURE__ */ T("div", {
124
127
  className: "space-y-5",
125
- children: [/* @__PURE__ */ w("div", { children: [
126
- /* @__PURE__ */ w("div", {
128
+ children: [/* @__PURE__ */ T("div", { children: [
129
+ /* @__PURE__ */ T("div", {
127
130
  className: "mb-2 flex items-center justify-between",
128
- children: [/* @__PURE__ */ C("label", {
131
+ children: [/* @__PURE__ */ w("label", {
129
132
  className: "text-sm font-medium text-text-primary",
130
133
  children: "Loan Amount"
131
- }), /* @__PURE__ */ C("span", {
134
+ }), /* @__PURE__ */ w("span", {
132
135
  className: "text-sm font-semibold text-text-primary",
133
- children: t(I)
136
+ children: t(L)
134
137
  })]
135
138
  }),
136
- /* @__PURE__ */ C("input", {
139
+ /* @__PURE__ */ w("input", {
137
140
  type: "range",
138
141
  min: 5e4,
139
- max: Math.max(P.maxAmount, 1e5),
142
+ max: Math.max(F.maxAmount, 1e5),
140
143
  step: 1e4,
141
- value: Math.min(I, P.maxAmount),
142
- onChange: (e) => L(Number(e.target.value)),
144
+ value: Math.min(L, F.maxAmount),
145
+ onChange: (e) => R(Number(e.target.value)),
143
146
  "aria-label": "Loan amount",
144
- className: k
147
+ className: A
145
148
  }),
146
- /* @__PURE__ */ w("div", {
149
+ /* @__PURE__ */ T("div", {
147
150
  className: "mt-1 flex justify-between text-xs text-text-secondary",
148
- children: [/* @__PURE__ */ C("span", { children: "₹50K" }), /* @__PURE__ */ w("span", { children: ["Max ", n(P.maxAmount)] })]
151
+ children: [/* @__PURE__ */ w("span", { children: "₹50K" }), /* @__PURE__ */ T("span", { children: ["Max ", n(F.maxAmount)] })]
149
152
  })
150
- ] }), /* @__PURE__ */ w("div", { children: [
151
- /* @__PURE__ */ w("div", {
153
+ ] }), /* @__PURE__ */ T("div", { children: [
154
+ /* @__PURE__ */ T("div", {
152
155
  className: "mb-2 flex items-center justify-between",
153
- children: [/* @__PURE__ */ C("label", {
156
+ children: [/* @__PURE__ */ w("label", {
154
157
  className: "text-sm font-medium text-text-primary",
155
158
  children: "Tenure (years)"
156
- }), /* @__PURE__ */ w("span", {
159
+ }), /* @__PURE__ */ T("span", {
157
160
  className: "text-sm font-semibold text-text-primary",
158
- children: [R, " years"]
161
+ children: [z, " years"]
159
162
  })]
160
163
  }),
161
- /* @__PURE__ */ C("input", {
164
+ /* @__PURE__ */ w("input", {
162
165
  type: "range",
163
166
  min: 1,
164
- max: P.maxTenure,
167
+ max: F.maxTenure,
165
168
  step: 1,
166
- value: Math.min(R, P.maxTenure),
167
- onChange: (e) => z(Number(e.target.value)),
169
+ value: Math.min(z, F.maxTenure),
170
+ onChange: (e) => B(Number(e.target.value)),
168
171
  "aria-label": "Tenure in years",
169
- className: k
172
+ className: A
170
173
  }),
171
- /* @__PURE__ */ w("div", {
174
+ /* @__PURE__ */ T("div", {
172
175
  className: "mt-1 flex justify-between text-xs text-text-secondary",
173
- children: [/* @__PURE__ */ C("span", { children: "1 yr" }), /* @__PURE__ */ w("span", { children: [
176
+ children: [/* @__PURE__ */ w("span", { children: "1 yr" }), /* @__PURE__ */ T("span", { children: [
174
177
  "Max ",
175
- P.maxTenure,
178
+ F.maxTenure,
176
179
  " yrs"
177
180
  ] })]
178
181
  })
179
182
  ] })]
180
- }), /* @__PURE__ */ w("div", {
183
+ }), /* @__PURE__ */ T("div", {
181
184
  className: "flex flex-col items-center justify-center rounded-lg bg-bg-sunken/50 p-6",
182
185
  children: [
183
- /* @__PURE__ */ C("p", {
186
+ /* @__PURE__ */ w("p", {
184
187
  className: "text-sm text-text-secondary",
185
188
  children: "Monthly EMI"
186
189
  }),
187
- /* @__PURE__ */ C("p", {
190
+ /* @__PURE__ */ w("p", {
188
191
  className: "my-2 text-4xl font-bold text-text-primary",
189
- children: t(U)
192
+ children: t(W)
190
193
  }),
191
- /* @__PURE__ */ w("div", {
194
+ /* @__PURE__ */ T("div", {
192
195
  className: "mt-4 grid w-full grid-cols-2 gap-4",
193
- children: [/* @__PURE__ */ w("div", {
196
+ children: [/* @__PURE__ */ T("div", {
194
197
  className: "text-center",
195
- children: [/* @__PURE__ */ C("p", {
198
+ children: [/* @__PURE__ */ w("p", {
196
199
  className: "text-xs text-text-secondary",
197
200
  children: "Total Payment"
198
- }), /* @__PURE__ */ C("p", {
201
+ }), /* @__PURE__ */ w("p", {
199
202
  className: "text-sm font-semibold text-text-primary",
200
- children: t(W)
203
+ children: t(G)
201
204
  })]
202
- }), /* @__PURE__ */ w("div", {
205
+ }), /* @__PURE__ */ T("div", {
203
206
  className: "text-center",
204
- children: [/* @__PURE__ */ C("p", {
207
+ children: [/* @__PURE__ */ w("p", {
205
208
  className: "text-xs text-text-secondary",
206
209
  children: "Total Interest"
207
- }), /* @__PURE__ */ C("p", {
210
+ }), /* @__PURE__ */ w("p", {
208
211
  className: "text-sm font-semibold text-status-error-text",
209
- children: t(G)
212
+ children: t(K)
210
213
  })]
211
214
  })]
212
215
  })
@@ -214,138 +217,138 @@ function M() {
214
217
  })]
215
218
  })]
216
219
  }),
217
- /* @__PURE__ */ w("div", {
220
+ /* @__PURE__ */ T("div", {
218
221
  className: "grid grid-cols-1 gap-6 lg:grid-cols-3",
219
- children: [/* @__PURE__ */ w("div", {
222
+ children: [/* @__PURE__ */ T("div", {
220
223
  className: "space-y-6 lg:col-span-2",
221
- children: [/* @__PURE__ */ w(D, {
224
+ children: [/* @__PURE__ */ T(O, {
222
225
  treatment: "plain",
223
226
  className: "border-border-seam p-6",
224
- children: [/* @__PURE__ */ C("h2", {
227
+ children: [/* @__PURE__ */ w("h2", {
225
228
  className: "mb-4 text-base font-semibold text-text-primary",
226
229
  children: "Loan Terms"
227
- }), /* @__PURE__ */ w("div", {
230
+ }), /* @__PURE__ */ T("div", {
228
231
  className: "grid grid-cols-2 gap-4 sm:grid-cols-3",
229
232
  children: [
230
- /* @__PURE__ */ w("div", {
233
+ /* @__PURE__ */ T("div", {
231
234
  className: "rounded-lg bg-bg-sunken/50 p-4",
232
- children: [/* @__PURE__ */ w("div", {
235
+ children: [/* @__PURE__ */ T("div", {
233
236
  className: "flex items-center gap-1.5 text-xs text-text-secondary",
234
- children: [/* @__PURE__ */ C(_, { className: "h-3.5 w-3.5" }), "Interest Rate"]
235
- }), /* @__PURE__ */ w("div", {
237
+ children: [/* @__PURE__ */ w(v, { className: "h-3.5 w-3.5" }), "Interest Rate"]
238
+ }), /* @__PURE__ */ T("div", {
236
239
  className: "mt-1 text-lg font-bold text-text-primary",
237
- children: [P.interestRate, "%"]
240
+ children: [F.interestRate, "%"]
238
241
  })]
239
242
  }),
240
- /* @__PURE__ */ w("div", {
243
+ /* @__PURE__ */ T("div", {
241
244
  className: "rounded-lg bg-bg-sunken/50 p-4",
242
- children: [/* @__PURE__ */ w("div", {
245
+ children: [/* @__PURE__ */ T("div", {
243
246
  className: "flex items-center gap-1.5 text-xs text-text-secondary",
244
- children: [/* @__PURE__ */ C(y, { className: "h-3.5 w-3.5" }), "EMI / Lakh"]
245
- }), /* @__PURE__ */ C("div", {
247
+ children: [/* @__PURE__ */ w(b, { className: "h-3.5 w-3.5" }), "EMI / Lakh"]
248
+ }), /* @__PURE__ */ w("div", {
246
249
  className: "mt-1 text-lg font-bold text-text-primary",
247
- children: P.emiPerLakh == null ? "—" : n(P.emiPerLakh)
250
+ children: F.emiPerLakh == null ? "—" : n(F.emiPerLakh)
248
251
  })]
249
252
  }),
250
- /* @__PURE__ */ w("div", {
253
+ /* @__PURE__ */ T("div", {
251
254
  className: "rounded-lg bg-bg-sunken/50 p-4",
252
- children: [/* @__PURE__ */ w("div", {
255
+ children: [/* @__PURE__ */ T("div", {
253
256
  className: "flex items-center gap-1.5 text-xs text-text-secondary",
254
- children: [/* @__PURE__ */ C(m, { className: "h-3.5 w-3.5" }), "Max Tenure"]
255
- }), /* @__PURE__ */ w("div", {
257
+ children: [/* @__PURE__ */ w(h, { className: "h-3.5 w-3.5" }), "Max Tenure"]
258
+ }), /* @__PURE__ */ T("div", {
256
259
  className: "mt-1 text-lg font-bold text-text-primary",
257
- children: [P.maxTenure, " yrs"]
260
+ children: [F.maxTenure, " yrs"]
258
261
  })]
259
262
  }),
260
- /* @__PURE__ */ w("div", {
263
+ /* @__PURE__ */ T("div", {
261
264
  className: "rounded-lg bg-bg-sunken/50 p-4",
262
- children: [/* @__PURE__ */ C("div", {
265
+ children: [/* @__PURE__ */ w("div", {
263
266
  className: "text-xs text-text-secondary",
264
267
  children: "Max Amount"
265
- }), /* @__PURE__ */ C("div", {
268
+ }), /* @__PURE__ */ w("div", {
266
269
  className: "mt-1 text-sm font-semibold text-text-primary",
267
- children: n(P.maxAmount)
270
+ children: n(F.maxAmount)
268
271
  })]
269
272
  }),
270
- /* @__PURE__ */ w("div", {
273
+ /* @__PURE__ */ T("div", {
271
274
  className: "rounded-lg bg-bg-sunken/50 p-4",
272
- children: [/* @__PURE__ */ C("div", {
275
+ children: [/* @__PURE__ */ w("div", {
273
276
  className: "text-xs text-text-secondary",
274
277
  children: "Processing Fee"
275
- }), /* @__PURE__ */ C("div", {
278
+ }), /* @__PURE__ */ w("div", {
276
279
  className: "mt-1 text-sm font-semibold text-text-primary",
277
- children: P.processingFee ?? "—"
280
+ children: F.processingFee ?? "—"
278
281
  })]
279
282
  }),
280
- /* @__PURE__ */ w("div", {
283
+ /* @__PURE__ */ T("div", {
281
284
  className: "rounded-lg bg-bg-sunken/50 p-4",
282
- children: [/* @__PURE__ */ C("div", {
285
+ children: [/* @__PURE__ */ w("div", {
283
286
  className: "text-xs text-text-secondary",
284
287
  children: "Prepayment"
285
- }), /* @__PURE__ */ C("div", {
286
- className: e("mt-1 text-sm font-semibold", P.prepaymentCharges === "None" ? "text-status-success-text" : "text-text-primary"),
287
- children: P.prepaymentCharges ?? "—"
288
+ }), /* @__PURE__ */ w("div", {
289
+ className: e("mt-1 text-sm font-semibold", F.prepaymentCharges === "None" ? "text-status-success-text" : "text-text-primary"),
290
+ children: F.prepaymentCharges ?? "—"
288
291
  })]
289
292
  })
290
293
  ]
291
294
  })]
292
- }), K.length > 0 && /* @__PURE__ */ w(D, {
295
+ }), q.length > 0 && /* @__PURE__ */ T(O, {
293
296
  treatment: "plain",
294
297
  className: "border-border-seam p-6",
295
- children: [/* @__PURE__ */ C("h2", {
298
+ children: [/* @__PURE__ */ w("h2", {
296
299
  className: "mb-4 text-base font-semibold text-text-primary",
297
300
  children: "Features"
298
- }), /* @__PURE__ */ C("ul", {
301
+ }), /* @__PURE__ */ w("ul", {
299
302
  className: "grid grid-cols-1 gap-2 sm:grid-cols-2",
300
- children: K.map((e, t) => /* @__PURE__ */ w("li", {
303
+ children: q.map((e, t) => /* @__PURE__ */ T("li", {
301
304
  className: "flex items-center gap-2 text-sm text-text-secondary",
302
- children: [/* @__PURE__ */ C(h, { className: "h-4 w-4 shrink-0 text-status-success-text" }), e]
305
+ children: [/* @__PURE__ */ w(g, { className: "h-4 w-4 shrink-0 text-status-success-text" }), e]
303
306
  }, t))
304
307
  })]
305
308
  })]
306
- }), /* @__PURE__ */ C("div", {
309
+ }), /* @__PURE__ */ w("div", {
307
310
  className: "space-y-6",
308
- children: /* @__PURE__ */ w(D, {
311
+ children: /* @__PURE__ */ T(O, {
309
312
  treatment: "plain",
310
313
  className: "border-border-seam p-5",
311
314
  children: [
312
- /* @__PURE__ */ C("h3", {
315
+ /* @__PURE__ */ w("h3", {
313
316
  className: "mb-2 text-base font-semibold text-text-primary",
314
317
  children: "Ready to apply?"
315
318
  }),
316
- /* @__PURE__ */ w("p", {
319
+ /* @__PURE__ */ T("p", {
317
320
  className: "mb-4 text-sm text-text-secondary",
318
321
  children: [
319
322
  "Applications are handled directly with ",
320
- P.bankName,
323
+ F.bankName,
321
324
  " through HousingVista Messages. Start an enquiry and the bank will guide you through eligibility and paperwork."
322
325
  ]
323
326
  }),
324
- /* @__PURE__ */ C(T, {
327
+ /* @__PURE__ */ w(E, {
325
328
  type: "button",
326
329
  variant: "default",
327
330
  className: "w-full justify-center",
328
- onClick: () => V(!0),
331
+ onClick: () => H(!0),
329
332
  children: "Apply Now"
330
333
  })
331
334
  ]
332
335
  })
333
336
  })]
334
337
  }),
335
- /* @__PURE__ */ C(c, {
336
- open: B,
337
- onOpenChange: V,
338
- entityId: P.id,
338
+ /* @__PURE__ */ w(l, {
339
+ open: V,
340
+ onOpenChange: H,
341
+ entityId: F.id,
339
342
  entityType: "housingvista-home-loan",
340
- title: P.bankName,
341
- pagePath: N.pathname,
342
- heading: `Apply with ${P.bankName}`,
343
- description: `Start your application with ${P.bankName}. Messages are saved and delivered in your inbox.`
343
+ title: F.bankName,
344
+ pagePath: P.pathname,
345
+ heading: `Apply with ${F.bankName}`,
346
+ description: `Start your application with ${F.bankName}. Messages are saved and delivered in your inbox.`
344
347
  })
345
348
  ]
346
349
  });
347
350
  }
348
351
  //#endregion
349
- export { M as HomeLoanDetailPage };
352
+ export { N as HomeLoanDetailPage };
350
353
 
351
354
  //# sourceMappingURL=HomeLoanDetailPage.js.map