@burdenoff/microfe-housingvista 2026.830.1 → 2026.830.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":"TransactionsPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/transactions/TransactionsPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA2DH,eAAO,MAAM,gBAAgB,mCAqkB5B,CAAC"}
1
+ {"version":3,"file":"TransactionsPage.d.ts","sourceRoot":"","sources":["../../../../src/housingvista/pages/transactions/TransactionsPage.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AA2DH,eAAO,MAAM,gBAAgB,mCAklB5B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TransactionsPage.js","names":[],"sources":["../../../../src/housingvista/pages/transactions/TransactionsPage.tsx"],"sourcesContent":["/**\n * HousingVista Transactions Listing Page\n * Migrated from legacy housingvista-frontend transactions.tsx\n * @module housingvista\n */\n\nimport { useState, useMemo, useEffect, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router';\nimport { useTr } from '../../../shared/hooks';\nimport {\n Plus,\n FileText,\n DollarSign,\n TrendingUp,\n CheckCircle,\n Eye,\n ArrowRight,\n Upload,\n Users,\n Shield,\n Building,\n} from 'lucide-react';\nimport {\n Button,\n EmphasisPanel,\n GlassCard,\n NextSteps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, DataTable, StatusBadge, EmptyState, StatCard } from '../../components';\nimport type { Column } from '../../components';\nimport { useTransactions, useCreateTransaction, useProperties, type TransactionFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { formatCurrency, formatDate } from '../../utils/helpers';\nimport type { Transaction, TransactionStatus, TransactionType } from '../../types';\nimport { MilestoneStepper, ProgressBar, parseEscrow, parseMilestones, milestoneProgress } from './milestones';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nconst TRANSACTION_TYPES: TransactionType[] = ['sale', 'purchase', 'rental', 'lease'];\nconst CREATE_STATUSES: TransactionStatus[] = ['draft', 'negotiation', 'under_contract', 'completed'];\n\n// ---- Status badge variant map ----\nconst statusVariantMap: Record<string, 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted'> = {\n draft: 'muted',\n negotiation: 'info',\n under_contract: 'warning',\n pending_approval: 'warning',\n approved: 'info',\n in_progress: 'info',\n completed: 'success',\n cancelled: 'error',\n disputed: 'error',\n};\n\nexport const TransactionsPage = () => {\n useTrackPageView('housingvista.transaction.viewed');\n const navigate = useNavigate();\n const tr = useTr();\n const pagination = useServerPagination(10);\n\n // ---- Search + status filter (server-side) ----\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [selectedStatus, setSelectedStatus] = useState<TransactionStatus | 'all'>('all');\n\n // Debounce the search box into the server filter (300ms).\n useEffect(() => {\n const handle = setTimeout(() => setDebouncedSearch(searchQuery), 300);\n return () => clearTimeout(handle);\n }, [searchQuery]);\n\n const filter: TransactionFilterInput = {\n search: debouncedSearch.trim() || undefined,\n status: selectedStatus === 'all' ? undefined : selectedStatus,\n };\n\n const { data: transactions, loading } = useTransactions({ filter, pagination: pagination.pagination });\n const { createTransaction, loading: creating } = useCreateTransaction();\n const { data: properties } = useProperties({ pagination: { limit: 50, offset: 0 } });\n\n // ---- Inline deal preview (right-hand panel, mirrors the concept mock) ----\n const [selectedId, setSelectedId] = useState<string | null>(null);\n useEffect(() => {\n if (transactions.length === 0) {\n if (selectedId !== null) setSelectedId(null);\n return;\n }\n if (!selectedId || !transactions.some((t) => t.id === selectedId)) {\n setSelectedId(transactions[0].id);\n }\n }, [transactions, selectedId]);\n const selectedTx = transactions.find((t) => t.id === selectedId) ?? null;\n\n // Reset to the first page whenever the search text or status tab changes.\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n pagination.setPage(1);\n };\n const selectStatus = (value: TransactionStatus | 'all') => {\n setSelectedStatus(value);\n pagination.setPage(1);\n };\n\n // ---- Create-transaction dialog state ----\n const [createOpen, setCreateOpen] = useState(false);\n const [propertyId, setPropertyId] = useState('');\n const [newTitle, setNewTitle] = useState('');\n const [newType, setNewType] = useState<TransactionType>('sale');\n const [newStatus, setNewStatus] = useState<TransactionStatus>('draft');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n\n const openCreate = () => {\n setPropertyId('');\n setNewTitle('');\n setNewType('sale');\n setNewStatus('draft');\n setAmount('');\n setCurrency('USD');\n setCreateOpen(true);\n };\n\n const handlePropertyChange = (id: string) => {\n setPropertyId(id);\n const picked = properties.find((p) => p.id === id);\n if (picked?.price?.currency) setCurrency(picked.price.currency);\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n if (!propertyId) {\n notify.warning(\n tr('housingvista.transactions.create.validation.selectPropertyTitle', 'Select a property'),\n tr('housingvista.transactions.create.validation.selectPropertyDesc', 'Choose the property this transaction is for.')\n );\n return;\n }\n if (!newTitle.trim()) {\n notify.warning(\n tr('housingvista.transactions.create.validation.addTitle', 'Add a title'),\n tr('housingvista.transactions.create.validation.addTitleDesc', 'Give this transaction a short, recognizable name.')\n );\n return;\n }\n const amountValue = Number(amount);\n if (!Number.isFinite(amountValue) || amountValue <= 0) {\n notify.warning(\n tr('housingvista.transactions.create.validation.validAmount', 'Enter a valid amount'),\n tr('housingvista.transactions.create.validation.validAmountDesc', 'The transaction amount must be greater than zero.')\n );\n return;\n }\n try {\n await createTransaction({\n propertyId,\n title: newTitle.trim(),\n type: newType,\n status: newStatus,\n amount: amountValue,\n currency: currency.trim() || 'USD',\n });\n notify.success(\n tr('housingvista.transactions.create.successTitle', 'Transaction created'),\n tr('housingvista.transactions.create.successDesc', '{{title}} was added to your transactions.', { title: newTitle.trim() })\n );\n setCreateOpen(false);\n } catch (err) {\n notify.error(\n tr('housingvista.transactions.create.errorTitle', 'Could not create transaction'),\n (err as Error).message\n );\n }\n };\n\n const statusTabs: { value: TransactionStatus | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.transactions.statusTabs.all', 'All') },\n { value: 'in_progress', label: tr('housingvista.transactions.statusTabs.inProgress', 'In Progress') },\n { value: 'completed', label: tr('housingvista.transactions.statusTabs.completed', 'Completed') },\n { value: 'cancelled', label: tr('housingvista.transactions.statusTabs.cancelled', 'Cancelled') },\n { value: 'negotiation', label: tr('housingvista.transactions.statusTabs.negotiation', 'Negotiation') },\n { value: 'pending_approval', label: tr('housingvista.transactions.statusTabs.pending', 'Pending') },\n ];\n\n const stats = useMemo(() => {\n const total = transactions.length;\n const totalValue = transactions.reduce((sum, t) => sum + t.amount, 0);\n const active = transactions.filter(\n (t) => t.status === 'in_progress' || t.status === 'negotiation' || t.status === 'pending_approval'\n ).length;\n const completed = transactions.filter((t) => t.status === 'completed').length;\n return { total, totalValue, active, completed };\n }, [transactions]);\n\n // ---- Table columns ----\n const columns: Column<Transaction>[] = [\n {\n key: 'id',\n header: tr('housingvista.transactions.table.id', 'ID'),\n render: (t) => <span className=\"font-medium text-text-primary\">#{t.id.split('-')[1]}</span>,\n },\n {\n key: 'property',\n header: tr('housingvista.transactions.table.property', 'Property'),\n render: (t) => (\n <div className=\"max-w-[200px]\">\n <div className=\"truncate text-sm font-medium text-text-primary\">{t.property.title}</div>\n <div className=\"truncate text-xs text-text-secondary\">\n {t.property.location.city}, {t.property.location.state}\n </div>\n </div>\n ),\n },\n {\n key: 'type',\n header: tr('housingvista.transactions.table.type', 'Type'),\n render: (t) => <span className=\"capitalize text-sm text-text-primary\">{t.type}</span>,\n },\n {\n key: 'status',\n header: tr('housingvista.transactions.table.status', 'Status'),\n render: (t) => (\n <StatusBadge label={t.status.replace(/_/g, ' ')} variant={statusVariantMap[t.status] ?? 'default'} dot />\n ),\n },\n {\n key: 'amount',\n header: tr('housingvista.transactions.table.amount', 'Amount'),\n sortable: true,\n render: (t) => <span className=\"font-semibold text-text-primary\">{formatCurrency(t.amount, t.currency)}</span>,\n },\n {\n key: 'progress',\n header: tr('housingvista.transactions.table.progress', 'Progress'),\n sortable: false,\n render: (t) => {\n const percent = milestoneProgress(parseMilestones(t.milestones));\n return (\n <div className=\"flex min-w-28 items-center gap-2\">\n <ProgressBar percent={percent} className=\"w-20\" />\n <span className=\"text-xs font-medium tabular-nums text-text-secondary\">{percent}%</span>\n </div>\n );\n },\n },\n {\n key: 'createdAt',\n header: tr('housingvista.transactions.table.date', 'Date'),\n sortable: true,\n render: (t) => <span className=\"text-sm text-text-secondary\">{formatDate(String(t.createdAt))}</span>,\n },\n {\n key: 'actions',\n header: '',\n sortable: false,\n render: (t) => (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(t.id);\n }}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n <Eye className=\"h-3.5 w-3.5\" />\n {tr('housingvista.transactions.table.view', 'View')}\n </button>\n ),\n },\n ];\n\n return (\n <PageLayout\n title={tr('housingvista.transactions.title', 'Transactions')}\n description={tr('housingvista.transactions.description', 'Manage your property transactions, escrow, and deals')}\n purpose={tr(\n 'housingvista.transactions.purpose',\n 'Track every buy, sell, and lease deal end to end — from offer and negotiation through escrow, approvals, and closing. Use this page to see what money is in motion, which deals need action, and the full history of each transaction.'\n )}\n actions={\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.transactions.actions.newTransaction', 'New Transaction')}\n </Button>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.transactions.stats.totalTransactions', 'Total Transactions')}\n value={stats.total}\n icon={<FileText className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.totalValue', 'Total Value')}\n value={stats.totalValue}\n prefix=\"$\"\n icon={<DollarSign className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.active', 'Active')}\n value={stats.active}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.completed', 'Completed')}\n value={stats.completed}\n icon={<CheckCircle className=\"h-5 w-5\" />}\n />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-transactions\"\n steps={[\n {\n id: 'focus-active',\n label: tr('housingvista.transactions.nextSteps.active', 'See deals that need attention'),\n description: tr(\n 'housingvista.transactions.nextSteps.activeDesc',\n 'Filter to in-progress deals where money is moving.'\n ),\n onClick: () => selectStatus('in_progress'),\n },\n {\n id: 'open-detail',\n label: tr('housingvista.transactions.nextSteps.open', 'Open a transaction'),\n description: tr(\n 'housingvista.transactions.nextSteps.openDesc',\n 'Drill into escrow, approvals, and the full timeline.'\n ),\n onClick: () => {\n const first = transactions[0];\n if (first) navigate(`../transactions/${first.id}`);\n },\n },\n {\n id: 'browse-properties',\n label: tr('housingvista.transactions.nextSteps.browse', 'Start a new deal from a listing'),\n description: tr('housingvista.transactions.nextSteps.browseDesc', 'Find a property to make an offer on.'),\n onClick: () => navigate('../properties'),\n },\n ]}\n />\n\n {/* Search */}\n <FilterBar\n searchValue={searchQuery}\n onSearchChange={handleSearchChange}\n searchPlaceholder={tr(\n 'housingvista.transactions.search.placeholder',\n 'Search by property or transaction ID...'\n )}\n />\n\n {/* Status Tabs */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => selectStatus(tab.value)}\n className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${\n selectedStatus === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Results info */}\n <p className=\"text-sm text-text-secondary\">\n {tr('housingvista.transactions.results.showing', 'Showing')} {transactions.length}{' '}\n {tr('housingvista.transactions.results.transactions', 'transactions')}\n {selectedTx ? ' — select a row to preview its deal timeline' : ''}\n </p>\n\n {/* Table + inline deal preview / Empty */}\n {transactions.length > 0 ? (\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_22rem]\">\n <div className=\"min-w-0\">\n <DataTable\n columns={columns}\n data={transactions}\n keyField=\"id\"\n onRowClick={(t) => setSelectedId(t.id)}\n pageSize={pagination.pageSize}\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: transactions.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n\n {selectedTx && (\n <GlassCard treatment=\"insight\" className=\"h-fit p-5 xl:sticky xl:top-6\">\n <div className=\"mb-4 flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.transactions.detail.title', 'Transaction Details')}\n </h3>\n <p className=\"truncate text-xs text-text-secondary\">\n #{selectedTx.id.split('-')[1] ?? selectedTx.id}\n </p>\n </div>\n <StatusBadge\n label={selectedTx.status.replace(/_/g, ' ')}\n variant={statusVariantMap[selectedTx.status] ?? 'default'}\n dot\n />\n </div>\n\n <div className=\"mb-4 flex items-center gap-2 text-sm text-text-primary\">\n <Building className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"truncate\">\n {selectedTx.property?.title ?? tr('housingvista.transactions.detail.propertyFallback', 'Property')}\n </span>\n </div>\n\n {/* Deal stage stepper */}\n <div className=\"mb-4 rounded-lg bg-bg-sunken/50 p-3\">\n <div className=\"mb-2 flex items-center gap-1.5 text-xs font-medium text-text-secondary\">\n <Shield className=\"h-3.5 w-3.5\" />\n {tr('housingvista.transactions.detail.dealStages', 'Deal stages')}\n </div>\n <MilestoneStepper milestones={parseMilestones(selectedTx.milestones)} />\n </div>\n\n {/* Escrow / amount headline */}\n {(() => {\n const escrow = parseEscrow(selectedTx.escrow);\n const hasEscrow = escrow?.amount != null;\n return (\n <div className=\"mb-4\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {hasEscrow\n ? tr('housingvista.transactions.detail.escrowAmount', 'Escrow amount')\n : tr('housingvista.transactions.detail.dealAmount', 'Deal amount')}\n </p>\n <p className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {formatCurrency(hasEscrow ? (escrow?.amount ?? 0) : selectedTx.amount, selectedTx.currency)}\n </p>\n {escrow?.status && (\n <StatusBadge\n label={tr('housingvista.transactions.detail.escrowStatus', 'Escrow {{status}}', { status: escrow.status })}\n variant=\"info\"\n className=\"mt-1\"\n />\n )}\n </div>\n );\n })()}\n\n <div className=\"grid grid-cols-2 gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`${selectedTx.id}#transaction-parties`)}>\n <Users className=\"h-4 w-4\" />\n <span className=\"ml-1\">{tr('housingvista.transactions.detail.parties', 'Parties')}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate(`${selectedTx.id}#transaction-documents`)}\n >\n <Upload className=\"h-4 w-4\" />\n <span className=\"ml-1\">{tr('housingvista.transactions.detail.documents', 'Documents')}</span>\n </Button>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n onClick={() => navigate(selectedTx.id)}\n >\n {tr('housingvista.transactions.detail.openFullDeal', 'Open full deal')}\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </GlassCard>\n )}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<FileText className=\"h-12 w-12\" />}\n title={tr('housingvista.transactions.empty.title', 'No transactions found')}\n description={tr(\n 'housingvista.transactions.empty.description',\n 'Try adjusting your search criteria or create a new transaction.'\n )}\n action={\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.transactions.empty.createNewTransaction', 'Create New Transaction')}\n </Button>\n }\n />\n )}\n\n {/* Create transaction dialog */}\n <ResponsiveDialog open={createOpen} onOpenChange={setCreateOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <form onSubmit={handleCreate}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {tr('housingvista.transactions.create.title', 'New transaction')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {tr(\n 'housingvista.transactions.create.description',\n 'Start a deal against a property. You can add documents, milestones, and escrow later.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.property', 'Property')} *\n </label>\n <select\n required\n value={propertyId}\n onChange={(e) => handlePropertyChange(e.target.value)}\n className={inputClass}\n >\n <option value=\"\" disabled>\n {properties.length > 0\n ? tr('housingvista.transactions.create.selectProperty', 'Select a property…')\n : tr('housingvista.transactions.create.noProperties', 'No properties available')}\n </option>\n {properties.map((p) => (\n <option key={p.id} value={p.id}>\n {p.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.titleField', 'Title')} *\n </label>\n <input\n type=\"text\"\n required\n placeholder={tr('housingvista.transactions.create.titlePlaceholder', 'e.g. Maple Court purchase')}\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n className={inputClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.type', 'Type')}\n </label>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as TransactionType)}\n className={inputClass}\n >\n {TRANSACTION_TYPES.map((option) => (\n <option key={option} value={option} className=\"capitalize\">\n {option}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.status', 'Status')}\n </label>\n <select\n value={newStatus}\n onChange={(e) => setNewStatus(e.target.value as TransactionStatus)}\n className={inputClass}\n >\n {CREATE_STATUSES.map((option) => (\n <option key={option} value={option}>\n {option.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.amount', 'Amount')} *\n </label>\n <input\n type=\"number\"\n required\n min={0}\n step=\"0.01\"\n placeholder=\"0.00\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n className={inputClass}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.currency', 'Currency')}\n </label>\n <input\n type=\"text\"\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n maxLength={3}\n className={inputClass}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setCreateOpen(false)}>\n {tr('housingvista.transactions.create.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={creating}>\n {creating\n ? tr('housingvista.transactions.create.creating', 'Creating…')\n : tr('housingvista.transactions.create.submit', 'Create transaction')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"TransactionsPage.js","names":[],"sources":["../../../../src/housingvista/pages/transactions/TransactionsPage.tsx"],"sourcesContent":["/**\n * HousingVista Transactions Listing Page\n * Migrated from legacy housingvista-frontend transactions.tsx\n * @module housingvista\n */\n\nimport { useState, useMemo, useEffect, type FormEvent } from 'react';\nimport { useNavigate } from 'react-router';\nimport { useTr } from '../../../shared/hooks';\nimport {\n Plus,\n FileText,\n DollarSign,\n TrendingUp,\n CheckCircle,\n Eye,\n ArrowRight,\n Upload,\n Users,\n Shield,\n Building,\n} from 'lucide-react';\nimport {\n Button,\n EmphasisPanel,\n GlassCard,\n NextSteps,\n ResponsiveDialog,\n ResponsiveDialogContent,\n ResponsiveDialogHeader,\n ResponsiveDialogTitle,\n ResponsiveDialogDescription,\n ResponsiveDialogFooter,\n} from '@burdenoff/fe-libs/ui';\nimport { PageLayout, FilterBar, DataTable, StatusBadge, EmptyState, StatCard } from '../../components';\nimport type { Column } from '../../components';\nimport { useTransactions, useCreateTransaction, useProperties, type TransactionFilterInput } from '../../hooks';\nimport { useServerPagination } from '../../hooks/useServerPagination';\nimport { notify } from '../../lib/toast';\nimport { formatCurrency, formatDate } from '../../utils/helpers';\nimport type { Transaction, TransactionStatus, TransactionType } from '../../types';\nimport { MilestoneStepper, ProgressBar, parseEscrow, parseMilestones, milestoneProgress } from './milestones';\nimport { useTrackPageView } from '../../hooks/useHousingVistaAnalytics';\n\nconst inputClass =\n 'h-10 w-full rounded-md border border-border-subtle bg-bg-surface px-3 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\n\nconst TRANSACTION_TYPES: TransactionType[] = ['sale', 'purchase', 'rental', 'lease'];\nconst CREATE_STATUSES: TransactionStatus[] = ['draft', 'negotiation', 'under_contract', 'completed'];\n\n// ---- Status badge variant map ----\nconst statusVariantMap: Record<string, 'success' | 'warning' | 'error' | 'info' | 'default' | 'muted'> = {\n draft: 'muted',\n negotiation: 'info',\n under_contract: 'warning',\n pending_approval: 'warning',\n approved: 'info',\n in_progress: 'info',\n completed: 'success',\n cancelled: 'error',\n disputed: 'error',\n};\n\nexport const TransactionsPage = () => {\n useTrackPageView('housingvista.transaction.viewed');\n const navigate = useNavigate();\n const tr = useTr();\n const pagination = useServerPagination(10);\n\n // ---- Search + status filter (server-side) ----\n const [searchQuery, setSearchQuery] = useState('');\n const [debouncedSearch, setDebouncedSearch] = useState('');\n const [selectedStatus, setSelectedStatus] = useState<TransactionStatus | 'all'>('all');\n\n // Debounce the search box into the server filter (300ms).\n useEffect(() => {\n const handle = setTimeout(() => setDebouncedSearch(searchQuery), 300);\n return () => clearTimeout(handle);\n }, [searchQuery]);\n\n const filter: TransactionFilterInput = {\n search: debouncedSearch.trim() || undefined,\n status: selectedStatus === 'all' ? undefined : selectedStatus,\n };\n\n const { data: transactions, loading } = useTransactions({ filter, pagination: pagination.pagination });\n const { createTransaction, loading: creating } = useCreateTransaction();\n const { data: properties } = useProperties({ pagination: { limit: 50, offset: 0 } });\n\n // ---- Inline deal preview (right-hand panel, mirrors the concept mock) ----\n const [selectedId, setSelectedId] = useState<string | null>(null);\n useEffect(() => {\n if (transactions.length === 0) {\n if (selectedId !== null) setSelectedId(null);\n return;\n }\n if (!selectedId || !transactions.some((t) => t.id === selectedId)) {\n setSelectedId(transactions[0].id);\n }\n }, [transactions, selectedId]);\n const selectedTx = transactions.find((t) => t.id === selectedId) ?? null;\n\n // Reset to the first page whenever the search text or status tab changes.\n const handleSearchChange = (value: string) => {\n setSearchQuery(value);\n pagination.setPage(1);\n };\n const selectStatus = (value: TransactionStatus | 'all') => {\n setSelectedStatus(value);\n pagination.setPage(1);\n };\n\n // ---- Create-transaction dialog state ----\n const [createOpen, setCreateOpen] = useState(false);\n const [propertyId, setPropertyId] = useState('');\n const [newTitle, setNewTitle] = useState('');\n const [newType, setNewType] = useState<TransactionType>('sale');\n const [newStatus, setNewStatus] = useState<TransactionStatus>('draft');\n const [amount, setAmount] = useState('');\n const [currency, setCurrency] = useState('USD');\n\n const openCreate = () => {\n setPropertyId('');\n setNewTitle('');\n setNewType('sale');\n setNewStatus('draft');\n setAmount('');\n setCurrency('USD');\n setCreateOpen(true);\n };\n\n const handlePropertyChange = (id: string) => {\n setPropertyId(id);\n const picked = properties.find((p) => p.id === id);\n if (picked?.price?.currency) setCurrency(picked.price.currency);\n };\n\n const handleCreate = async (e: FormEvent) => {\n e.preventDefault();\n if (!propertyId) {\n notify.warning(\n tr('housingvista.transactions.create.validation.selectPropertyTitle', 'Select a property'),\n tr(\n 'housingvista.transactions.create.validation.selectPropertyDesc',\n 'Choose the property this transaction is for.'\n )\n );\n return;\n }\n if (!newTitle.trim()) {\n notify.warning(\n tr('housingvista.transactions.create.validation.addTitle', 'Add a title'),\n tr(\n 'housingvista.transactions.create.validation.addTitleDesc',\n 'Give this transaction a short, recognizable name.'\n )\n );\n return;\n }\n const amountValue = Number(amount);\n if (!Number.isFinite(amountValue) || amountValue <= 0) {\n notify.warning(\n tr('housingvista.transactions.create.validation.validAmount', 'Enter a valid amount'),\n tr(\n 'housingvista.transactions.create.validation.validAmountDesc',\n 'The transaction amount must be greater than zero.'\n )\n );\n return;\n }\n try {\n await createTransaction({\n propertyId,\n title: newTitle.trim(),\n type: newType,\n status: newStatus,\n amount: amountValue,\n currency: currency.trim() || 'USD',\n });\n notify.success(\n tr('housingvista.transactions.create.successTitle', 'Transaction created'),\n tr('housingvista.transactions.create.successDesc', '{{title}} was added to your transactions.', {\n title: newTitle.trim(),\n })\n );\n setCreateOpen(false);\n } catch (err) {\n notify.error(\n tr('housingvista.transactions.create.errorTitle', 'Could not create transaction'),\n (err as Error).message\n );\n }\n };\n\n const statusTabs: { value: TransactionStatus | 'all'; label: string }[] = [\n { value: 'all', label: tr('housingvista.transactions.statusTabs.all', 'All') },\n { value: 'in_progress', label: tr('housingvista.transactions.statusTabs.inProgress', 'In Progress') },\n { value: 'completed', label: tr('housingvista.transactions.statusTabs.completed', 'Completed') },\n { value: 'cancelled', label: tr('housingvista.transactions.statusTabs.cancelled', 'Cancelled') },\n { value: 'negotiation', label: tr('housingvista.transactions.statusTabs.negotiation', 'Negotiation') },\n { value: 'pending_approval', label: tr('housingvista.transactions.statusTabs.pending', 'Pending') },\n ];\n\n const stats = useMemo(() => {\n const total = transactions.length;\n const totalValue = transactions.reduce((sum, t) => sum + t.amount, 0);\n const active = transactions.filter(\n (t) => t.status === 'in_progress' || t.status === 'negotiation' || t.status === 'pending_approval'\n ).length;\n const completed = transactions.filter((t) => t.status === 'completed').length;\n return { total, totalValue, active, completed };\n }, [transactions]);\n\n // ---- Table columns ----\n const columns: Column<Transaction>[] = [\n {\n key: 'id',\n header: tr('housingvista.transactions.table.id', 'ID'),\n render: (t) => <span className=\"font-medium text-text-primary\">#{t.id.split('-')[1]}</span>,\n },\n {\n key: 'property',\n header: tr('housingvista.transactions.table.property', 'Property'),\n render: (t) => (\n <div className=\"max-w-[200px]\">\n <div className=\"truncate text-sm font-medium text-text-primary\">{t.property.title}</div>\n <div className=\"truncate text-xs text-text-secondary\">\n {t.property.location.city}, {t.property.location.state}\n </div>\n </div>\n ),\n },\n {\n key: 'type',\n header: tr('housingvista.transactions.table.type', 'Type'),\n render: (t) => <span className=\"capitalize text-sm text-text-primary\">{t.type}</span>,\n },\n {\n key: 'status',\n header: tr('housingvista.transactions.table.status', 'Status'),\n render: (t) => (\n <StatusBadge label={t.status.replace(/_/g, ' ')} variant={statusVariantMap[t.status] ?? 'default'} dot />\n ),\n },\n {\n key: 'amount',\n header: tr('housingvista.transactions.table.amount', 'Amount'),\n sortable: true,\n render: (t) => <span className=\"font-semibold text-text-primary\">{formatCurrency(t.amount, t.currency)}</span>,\n },\n {\n key: 'progress',\n header: tr('housingvista.transactions.table.progress', 'Progress'),\n sortable: false,\n render: (t) => {\n const percent = milestoneProgress(parseMilestones(t.milestones));\n return (\n <div className=\"flex min-w-28 items-center gap-2\">\n <ProgressBar percent={percent} className=\"w-20\" />\n <span className=\"text-xs font-medium tabular-nums text-text-secondary\">{percent}%</span>\n </div>\n );\n },\n },\n {\n key: 'createdAt',\n header: tr('housingvista.transactions.table.date', 'Date'),\n sortable: true,\n render: (t) => <span className=\"text-sm text-text-secondary\">{formatDate(String(t.createdAt))}</span>,\n },\n {\n key: 'actions',\n header: '',\n sortable: false,\n render: (t) => (\n <button\n onClick={(e) => {\n e.stopPropagation();\n navigate(t.id);\n }}\n className=\"inline-flex items-center gap-1 text-xs font-medium text-text-secondary transition-colors hover:text-text-primary\"\n >\n <Eye className=\"h-3.5 w-3.5\" />\n {tr('housingvista.transactions.table.view', 'View')}\n </button>\n ),\n },\n ];\n\n return (\n <PageLayout\n title={tr('housingvista.transactions.title', 'Transactions')}\n description={tr('housingvista.transactions.description', 'Manage your property transactions, escrow, and deals')}\n purpose={tr(\n 'housingvista.transactions.purpose',\n 'Track every buy, sell, and lease deal end to end — from offer and negotiation through escrow, approvals, and closing. Use this page to see what money is in motion, which deals need action, and the full history of each transaction.'\n )}\n actions={\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.transactions.actions.newTransaction', 'New Transaction')}\n </Button>\n }\n >\n {/* Stats — primary insight zone (one EmphasisPanel per page) */}\n <EmphasisPanel className=\"p-4\">\n <div className=\"grid grid-cols-2 gap-4 lg:grid-cols-4\">\n <StatCard\n label={tr('housingvista.transactions.stats.totalTransactions', 'Total Transactions')}\n value={stats.total}\n icon={<FileText className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.totalValue', 'Total Value')}\n value={stats.totalValue}\n prefix=\"$\"\n icon={<DollarSign className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.active', 'Active')}\n value={stats.active}\n icon={<TrendingUp className=\"h-5 w-5\" />}\n />\n <StatCard\n label={tr('housingvista.transactions.stats.completed', 'Completed')}\n value={stats.completed}\n icon={<CheckCircle className=\"h-5 w-5\" />}\n />\n </div>\n </EmphasisPanel>\n\n <NextSteps\n storageKey=\"housingvista-transactions\"\n steps={[\n {\n id: 'focus-active',\n label: tr('housingvista.transactions.nextSteps.active', 'See deals that need attention'),\n description: tr(\n 'housingvista.transactions.nextSteps.activeDesc',\n 'Filter to in-progress deals where money is moving.'\n ),\n onClick: () => selectStatus('in_progress'),\n },\n {\n id: 'open-detail',\n label: tr('housingvista.transactions.nextSteps.open', 'Open a transaction'),\n description: tr(\n 'housingvista.transactions.nextSteps.openDesc',\n 'Drill into escrow, approvals, and the full timeline.'\n ),\n onClick: () => {\n const first = transactions[0];\n if (first) navigate(`../transactions/${first.id}`);\n },\n },\n {\n id: 'browse-properties',\n label: tr('housingvista.transactions.nextSteps.browse', 'Start a new deal from a listing'),\n description: tr('housingvista.transactions.nextSteps.browseDesc', 'Find a property to make an offer on.'),\n onClick: () => navigate('../properties'),\n },\n ]}\n />\n\n {/* Search */}\n <FilterBar\n searchValue={searchQuery}\n onSearchChange={handleSearchChange}\n searchPlaceholder={tr(\n 'housingvista.transactions.search.placeholder',\n 'Search by property or transaction ID...'\n )}\n />\n\n {/* Status Tabs */}\n <div className=\"flex flex-wrap items-center gap-2\">\n {statusTabs.map((tab) => (\n <button\n key={tab.value}\n onClick={() => selectStatus(tab.value)}\n className={`rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${\n selectedStatus === tab.value\n ? 'bg-action-primary-bg text-action-primary-text'\n : 'text-text-secondary hover:bg-bg-sunken hover:text-text-primary'\n }`}\n >\n {tab.label}\n </button>\n ))}\n </div>\n\n {/* Results info */}\n <p className=\"text-sm text-text-secondary\">\n {tr('housingvista.transactions.results.showing', 'Showing')} {transactions.length}{' '}\n {tr('housingvista.transactions.results.transactions', 'transactions')}\n {selectedTx ? ' — select a row to preview its deal timeline' : ''}\n </p>\n\n {/* Table + inline deal preview / Empty */}\n {transactions.length > 0 ? (\n <div className=\"grid grid-cols-1 gap-6 xl:grid-cols-[minmax(0,1fr)_22rem]\">\n <div className=\"min-w-0\">\n <DataTable\n columns={columns}\n data={transactions}\n keyField=\"id\"\n onRowClick={(t) => setSelectedId(t.id)}\n pageSize={pagination.pageSize}\n serverPagination={{\n page: pagination.page,\n pageSize: pagination.pageSize,\n hasNextPage: transactions.length >= pagination.pageSize,\n loading,\n onPageChange: pagination.setPage,\n onPageSizeChange: pagination.setPageSize,\n }}\n />\n </div>\n\n {selectedTx && (\n <GlassCard treatment=\"insight\" className=\"h-fit p-5 xl:sticky xl:top-6\">\n <div className=\"mb-4 flex items-start justify-between gap-2\">\n <div className=\"min-w-0\">\n <h3 className=\"text-base font-semibold text-text-primary\">\n {tr('housingvista.transactions.detail.title', 'Transaction Details')}\n </h3>\n <p className=\"truncate text-xs text-text-secondary\">\n #{selectedTx.id.split('-')[1] ?? selectedTx.id}\n </p>\n </div>\n <StatusBadge\n label={selectedTx.status.replace(/_/g, ' ')}\n variant={statusVariantMap[selectedTx.status] ?? 'default'}\n dot\n />\n </div>\n\n <div className=\"mb-4 flex items-center gap-2 text-sm text-text-primary\">\n <Building className=\"h-4 w-4 shrink-0 text-text-secondary\" />\n <span className=\"truncate\">\n {selectedTx.property?.title ?? tr('housingvista.transactions.detail.propertyFallback', 'Property')}\n </span>\n </div>\n\n {/* Deal stage stepper */}\n <div className=\"mb-4 rounded-lg bg-bg-sunken/50 p-3\">\n <div className=\"mb-2 flex items-center gap-1.5 text-xs font-medium text-text-secondary\">\n <Shield className=\"h-3.5 w-3.5\" />\n {tr('housingvista.transactions.detail.dealStages', 'Deal stages')}\n </div>\n <MilestoneStepper milestones={parseMilestones(selectedTx.milestones)} />\n </div>\n\n {/* Escrow / amount headline */}\n {(() => {\n const escrow = parseEscrow(selectedTx.escrow);\n const hasEscrow = escrow?.amount != null;\n return (\n <div className=\"mb-4\">\n <p className=\"text-xs font-medium text-text-secondary\">\n {hasEscrow\n ? tr('housingvista.transactions.detail.escrowAmount', 'Escrow amount')\n : tr('housingvista.transactions.detail.dealAmount', 'Deal amount')}\n </p>\n <p className=\"text-2xl font-bold tabular-nums text-text-primary\">\n {formatCurrency(hasEscrow ? (escrow?.amount ?? 0) : selectedTx.amount, selectedTx.currency)}\n </p>\n {escrow?.status && (\n <StatusBadge\n label={tr('housingvista.transactions.detail.escrowStatus', 'Escrow {{status}}', {\n status: escrow.status,\n })}\n variant=\"info\"\n className=\"mt-1\"\n />\n )}\n </div>\n );\n })()}\n\n <div className=\"grid grid-cols-2 gap-2\">\n <Button type=\"button\" size=\"sm\" onClick={() => navigate(`${selectedTx.id}#transaction-parties`)}>\n <Users className=\"h-4 w-4\" />\n <span className=\"ml-1\">{tr('housingvista.transactions.detail.parties', 'Parties')}</span>\n </Button>\n <Button\n type=\"button\"\n variant=\"outline\"\n size=\"sm\"\n onClick={() => navigate(`${selectedTx.id}#transaction-documents`)}\n >\n <Upload className=\"h-4 w-4\" />\n <span className=\"ml-1\">{tr('housingvista.transactions.detail.documents', 'Documents')}</span>\n </Button>\n </div>\n <Button\n type=\"button\"\n variant=\"ghost\"\n size=\"sm\"\n className=\"mt-2 w-full\"\n onClick={() => navigate(selectedTx.id)}\n >\n {tr('housingvista.transactions.detail.openFullDeal', 'Open full deal')}\n <ArrowRight className=\"ml-1 h-4 w-4\" />\n </Button>\n </GlassCard>\n )}\n </div>\n ) : (\n <EmptyState\n illustration=\"empty-search\"\n icon={<FileText className=\"h-12 w-12\" />}\n title={tr('housingvista.transactions.empty.title', 'No transactions found')}\n description={tr(\n 'housingvista.transactions.empty.description',\n 'Try adjusting your search criteria or create a new transaction.'\n )}\n action={\n <Button type=\"button\" onClick={openCreate} className=\"gap-2\">\n <Plus className=\"h-4 w-4\" />\n {tr('housingvista.transactions.empty.createNewTransaction', 'Create New Transaction')}\n </Button>\n }\n />\n )}\n\n {/* Create transaction dialog */}\n <ResponsiveDialog open={createOpen} onOpenChange={setCreateOpen}>\n <ResponsiveDialogContent className=\"sm:max-w-lg\">\n <form onSubmit={handleCreate}>\n <ResponsiveDialogHeader>\n <ResponsiveDialogTitle>\n {tr('housingvista.transactions.create.title', 'New transaction')}\n </ResponsiveDialogTitle>\n <ResponsiveDialogDescription>\n {tr(\n 'housingvista.transactions.create.description',\n 'Start a deal against a property. You can add documents, milestones, and escrow later.'\n )}\n </ResponsiveDialogDescription>\n </ResponsiveDialogHeader>\n <div className=\"space-y-3 py-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.property', 'Property')} *\n </label>\n <select\n required\n value={propertyId}\n onChange={(e) => handlePropertyChange(e.target.value)}\n className={inputClass}\n >\n <option value=\"\" disabled>\n {properties.length > 0\n ? tr('housingvista.transactions.create.selectProperty', 'Select a property…')\n : tr('housingvista.transactions.create.noProperties', 'No properties available')}\n </option>\n {properties.map((p) => (\n <option key={p.id} value={p.id}>\n {p.title}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.titleField', 'Title')} *\n </label>\n <input\n type=\"text\"\n required\n placeholder={tr('housingvista.transactions.create.titlePlaceholder', 'e.g. Maple Court purchase')}\n value={newTitle}\n onChange={(e) => setNewTitle(e.target.value)}\n className={inputClass}\n />\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.type', 'Type')}\n </label>\n <select\n value={newType}\n onChange={(e) => setNewType(e.target.value as TransactionType)}\n className={inputClass}\n >\n {TRANSACTION_TYPES.map((option) => (\n <option key={option} value={option} className=\"capitalize\">\n {option}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.status', 'Status')}\n </label>\n <select\n value={newStatus}\n onChange={(e) => setNewStatus(e.target.value as TransactionStatus)}\n className={inputClass}\n >\n {CREATE_STATUSES.map((option) => (\n <option key={option} value={option}>\n {option.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n </div>\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.amount', 'Amount')} *\n </label>\n <input\n type=\"number\"\n required\n min={0}\n step=\"0.01\"\n placeholder=\"0.00\"\n value={amount}\n onChange={(e) => setAmount(e.target.value)}\n className={inputClass}\n />\n </div>\n <div>\n <label className=\"mb-1.5 block text-sm font-medium text-text-primary\">\n {tr('housingvista.transactions.create.currency', 'Currency')}\n </label>\n <input\n type=\"text\"\n placeholder=\"USD\"\n value={currency}\n onChange={(e) => setCurrency(e.target.value.toUpperCase())}\n maxLength={3}\n className={inputClass}\n />\n </div>\n </div>\n </div>\n <ResponsiveDialogFooter>\n <Button type=\"button\" variant=\"outline\" onClick={() => setCreateOpen(false)}>\n {tr('housingvista.transactions.create.cancel', 'Cancel')}\n </Button>\n <Button type=\"submit\" disabled={creating}>\n {creating\n ? tr('housingvista.transactions.create.creating', 'Creating…')\n : tr('housingvista.transactions.create.submit', 'Create transaction')}\n </Button>\n </ResponsiveDialogFooter>\n </form>\n </ResponsiveDialogContent>\n </ResponsiveDialog>\n </PageLayout>\n );\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTr.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useTr.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,IAAI,CACvB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KACrC,MAAM,CAcV"}
1
+ {"version":3,"file":"useTr.d.ts","sourceRoot":"","sources":["../../../src/shared/hooks/useTr.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,KAAK,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,KAAK,MAAM,CAc3G"}
@@ -1 +1 @@
1
- {"version":3,"file":"useTr.js","names":[],"sources":["../../../src/shared/hooks/useTr.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n/**\n * useTr — translation hook with fallback semantics.\n *\n * Wraps `useI18n().t()` so that when a key has no translation (i.e. the\n * provider returns the key itself), the caller's English fallback is used\n * instead. This keeps consumer call sites consistent and avoids leaking\n * untranslated keys into the UI.\n *\n * Supports optional interpolation params using `{{key}}` placeholders.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('housingvista.dashboard.title', 'Dashboard')}</h1>;\n * return <p>{tr('housingvista.delete.confirm', 'Delete {{count}} items?', { count: 5 })}</p>;\n */\nexport function useTr(): (\n key: string,\n fallback: string,\n params?: Record<string, string | number>\n) => string {\n const { t } = useI18n();\n return useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key);\n const raw = translated === key ? fallback : translated;\n if (!params) return raw;\n return Object.entries(params).reduce(\n (str, [k, v]) => str.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, 'g'), String(v)),\n raw\n );\n },\n [t]\n );\n}\n"],"mappings":";;;AAkBA,SAAgB,IAIJ;CACV,IAAM,EAAE,SAAM,GAAS;AACvB,QAAO,GACJ,GAAa,GAAkB,MAAqD;EACnF,IAAM,IAAa,EAAE,EAAI,EACnB,IAAM,MAAe,IAAM,IAAW;AAE5C,SADK,IACE,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAG,OAAO,EAAI,QAAY,OAAO,SAAS,EAAE,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC,EAC5E,EACD,GAJmB;IAMtB,CAAC,EAAE,CACJ"}
1
+ {"version":3,"file":"useTr.js","names":[],"sources":["../../../src/shared/hooks/useTr.ts"],"sourcesContent":["import { useCallback } from 'react';\nimport { useI18n } from '@burdenoff/fe-libs/shared/providers/shell/I18nProvider';\n\n/**\n * useTr — translation hook with fallback semantics.\n *\n * Wraps `useI18n().t()` so that when a key has no translation (i.e. the\n * provider returns the key itself), the caller's English fallback is used\n * instead. This keeps consumer call sites consistent and avoids leaking\n * untranslated keys into the UI.\n *\n * Supports optional interpolation params using `{{key}}` placeholders.\n *\n * @example\n * const tr = useTr();\n * return <h1>{tr('housingvista.dashboard.title', 'Dashboard')}</h1>;\n * return <p>{tr('housingvista.delete.confirm', 'Delete {{count}} items?', { count: 5 })}</p>;\n */\nexport function useTr(): (key: string, fallback: string, params?: Record<string, string | number>) => string {\n const { t } = useI18n();\n return useCallback(\n (key: string, fallback: string, params?: Record<string, string | number>): string => {\n const translated = t(key);\n const raw = translated === key ? fallback : translated;\n if (!params) return raw;\n return Object.entries(params).reduce(\n (str, [k, v]) => str.replace(new RegExp(`\\\\{\\\\{${k}\\\\}\\\\}`, 'g'), String(v)),\n raw\n );\n },\n [t]\n );\n}\n"],"mappings":";;;AAkBA,SAAgB,IAA6F;CAC3G,IAAM,EAAE,SAAM,GAAS;AACvB,QAAO,GACJ,GAAa,GAAkB,MAAqD;EACnF,IAAM,IAAa,EAAE,EAAI,EACnB,IAAM,MAAe,IAAM,IAAW;AAE5C,SADK,IACE,OAAO,QAAQ,EAAO,CAAC,QAC3B,GAAK,CAAC,GAAG,OAAO,EAAI,QAAY,OAAO,SAAS,EAAE,SAAS,IAAI,EAAE,OAAO,EAAE,CAAC,EAC5E,EACD,GAJmB;IAMtB,CAAC,EAAE,CACJ"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@burdenoff/microfe-housingvista",
3
- "version": "2026.830.1",
3
+ "version": "2026.830.2",
4
4
  "description": "Burdenoff HousingVista Microfrontend - Comprehensive real estate platform for property management, investment, and transactions",
5
5
  "type": "module",
6
6
  "files": [