@wealthx/shadcn 1.4.1 → 1.5.1

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 (430) hide show
  1. package/.turbo/turbo-build.log +356 -176
  2. package/CHANGELOG.md +12 -0
  3. package/dist/chunk-2A53WPEC.mjs +182 -0
  4. package/dist/{chunk-SIVYAI3M.mjs → chunk-2LLFNGJZ.mjs} +15 -15
  5. package/dist/chunk-2QNOPXMQ.mjs +360 -0
  6. package/dist/{chunk-K5QV4TT6.mjs → chunk-2WCIORP7.mjs} +29 -4
  7. package/dist/{chunk-5NF6T2RS.mjs → chunk-3AREQTZU.mjs} +8 -8
  8. package/dist/{chunk-2EM2FRU6.mjs → chunk-3WGFIFP6.mjs} +5 -5
  9. package/dist/{chunk-K4KOD3KR.mjs → chunk-42NEC57Y.mjs} +44 -25
  10. package/dist/{chunk-FL6DZFJK.mjs → chunk-46Q4335I.mjs} +121 -39
  11. package/dist/chunk-4DO3WM7V.mjs +48 -0
  12. package/dist/chunk-5FHBC6DY.mjs +68 -0
  13. package/dist/chunk-5SAYZ4CI.mjs +40 -0
  14. package/dist/chunk-5WMFKQZ6.mjs +180 -0
  15. package/dist/chunk-623YVI5O.mjs +43 -0
  16. package/dist/{chunk-SFH2NJEJ.mjs → chunk-6OSULDEO.mjs} +3 -3
  17. package/dist/{chunk-UALR6JGV.mjs → chunk-6SR4K5T5.mjs} +1 -1
  18. package/dist/{chunk-D2NSIIXG.mjs → chunk-7KT5HPYM.mjs} +11 -11
  19. package/dist/chunk-A6ER36CW.mjs +456 -0
  20. package/dist/{chunk-QX7IFQSF.mjs → chunk-AHKHVBWR.mjs} +4 -4
  21. package/dist/chunk-AHSCWXYJ.mjs +113 -0
  22. package/dist/{chunk-7GWRPXHD.mjs → chunk-AL6GOL2Y.mjs} +1 -1
  23. package/dist/{chunk-OIKBW2QD.mjs → chunk-AUEUTZIC.mjs} +13 -13
  24. package/dist/{chunk-FYPSTTEJ.mjs → chunk-B7DD3ODQ.mjs} +1 -1
  25. package/dist/{chunk-TLAWKTSA.mjs → chunk-BD3DWDT4.mjs} +3 -3
  26. package/dist/{chunk-S2FKV4M5.mjs → chunk-BDESHD25.mjs} +4 -4
  27. package/dist/{chunk-OKTJFDPN.mjs → chunk-BFB3UH7V.mjs} +2 -2
  28. package/dist/{chunk-DGNHGNYH.mjs → chunk-C6SWS7OW.mjs} +1 -1
  29. package/dist/chunk-CDVG7SFT.mjs +271 -0
  30. package/dist/chunk-CUSHAIUL.mjs +109 -0
  31. package/dist/{chunk-QXKGOMUX.mjs → chunk-CW32WTZU.mjs} +4 -4
  32. package/dist/{chunk-SET2ANTY.mjs → chunk-D447W45Z.mjs} +3 -3
  33. package/dist/{chunk-RCAOCHWA.mjs → chunk-DFL5CV75.mjs} +18 -18
  34. package/dist/chunk-DYSVJ473.mjs +162 -0
  35. package/dist/chunk-E3PQDBYI.mjs +288 -0
  36. package/dist/chunk-EMYBNPIA.mjs +83 -0
  37. package/dist/chunk-EUYPMDQG.mjs +348 -0
  38. package/dist/{chunk-XYPW2XA5.mjs → chunk-EW72FINW.mjs} +11 -11
  39. package/dist/chunk-F24U4QQQ.mjs +234 -0
  40. package/dist/{chunk-VB5M6OZQ.mjs → chunk-F4O2YPXJ.mjs} +1 -1
  41. package/dist/chunk-FFXTQTB4.mjs +84 -0
  42. package/dist/{chunk-ZOWL2L5J.mjs → chunk-FYUSF5KO.mjs} +5 -1
  43. package/dist/{chunk-FTPBQVQ6.mjs → chunk-GNER6MCO.mjs} +1 -1
  44. package/dist/{chunk-2D3HQPFN.mjs → chunk-HF4FUBCY.mjs} +5 -5
  45. package/dist/{chunk-RSUIPKGX.mjs → chunk-HNDTLT5X.mjs} +1 -1
  46. package/dist/{chunk-N6Q5IPKT.mjs → chunk-HO6S3ECM.mjs} +46 -18
  47. package/dist/{chunk-L4NSRQ3T.mjs → chunk-HROG643K.mjs} +1 -1
  48. package/dist/chunk-I2EKKSEF.mjs +148 -0
  49. package/dist/{chunk-QTRSCVQ3.mjs → chunk-I3UDLWQ7.mjs} +1 -1
  50. package/dist/{chunk-AE7MASLF.mjs → chunk-IQGKOT7A.mjs} +9 -6
  51. package/dist/chunk-IXR4BQSQ.mjs +290 -0
  52. package/dist/{chunk-4MM7LHM5.mjs → chunk-J5NW5NCT.mjs} +1 -1
  53. package/dist/{chunk-OLKMCXAR.mjs → chunk-JTG5R5YV.mjs} +24 -24
  54. package/dist/chunk-JUBUN65Q.mjs +106 -0
  55. package/dist/chunk-K7TWMLLW.mjs +520 -0
  56. package/dist/{chunk-BOW7U26Y.mjs → chunk-K7WSRWOU.mjs} +4 -4
  57. package/dist/{chunk-NTYQWVLI.mjs → chunk-KAD26MCC.mjs} +1 -1
  58. package/dist/{chunk-KCWNDYPZ.mjs → chunk-KB7MZMED.mjs} +4 -4
  59. package/dist/chunk-KCKYGQVQ.mjs +61 -0
  60. package/dist/{chunk-VY5NEUP7.mjs → chunk-KLJLDNCA.mjs} +1 -1
  61. package/dist/chunk-LLAGF6BA.mjs +49 -0
  62. package/dist/{chunk-G27TSQLQ.mjs → chunk-M4LTX3MH.mjs} +1 -1
  63. package/dist/{chunk-YIZHS72Z.mjs → chunk-MHHA7QGO.mjs} +94 -54
  64. package/dist/{chunk-P2N2PEFY.mjs → chunk-NCUH54IZ.mjs} +4 -4
  65. package/dist/{chunk-PNRUH7JY.mjs → chunk-OECGKCVF.mjs} +5 -5
  66. package/dist/{chunk-YE67AALL.mjs → chunk-OL65UQHQ.mjs} +10 -10
  67. package/dist/{chunk-LQULK2E3.mjs → chunk-OYBIUEGE.mjs} +1 -1
  68. package/dist/{chunk-LR6LHDP3.mjs → chunk-PGR53HMH.mjs} +7 -7
  69. package/dist/chunk-PUJ42INK.mjs +141 -0
  70. package/dist/{chunk-M4VYX2PV.mjs → chunk-PV3Y7QGK.mjs} +2 -2
  71. package/dist/{chunk-UJZ4UHWI.mjs → chunk-PV7PNA6K.mjs} +4 -4
  72. package/dist/{chunk-6HIOM2HL.mjs → chunk-Q35PNFJ7.mjs} +1 -1
  73. package/dist/{chunk-JZY6TNIS.mjs → chunk-Q5SGEIJV.mjs} +27 -27
  74. package/dist/{chunk-ZFCDYW6N.mjs → chunk-QAX6HCUH.mjs} +1 -1
  75. package/dist/chunk-QHJDGB54.mjs +135 -0
  76. package/dist/chunk-QQSOZQOC.mjs +27 -0
  77. package/dist/chunk-RUX3OLVZ.mjs +59 -0
  78. package/dist/{chunk-QOJ2DQD6.mjs → chunk-S4CTM3UE.mjs} +5 -0
  79. package/dist/{chunk-ZEDMKQK2.mjs → chunk-TAX3KL66.mjs} +1 -1
  80. package/dist/chunk-TC43SMIN.mjs +133 -0
  81. package/dist/chunk-TGVXRD53.mjs +174 -0
  82. package/dist/{chunk-K5VHK7CM.mjs → chunk-TLYSVRSK.mjs} +12 -12
  83. package/dist/{chunk-YCWLFG27.mjs → chunk-TOIVHWNC.mjs} +1 -1
  84. package/dist/chunk-TXUBGKB7.mjs +160 -0
  85. package/dist/chunk-UEREFDAE.mjs +75 -0
  86. package/dist/chunk-UTCQN6XU.mjs +123 -0
  87. package/dist/{chunk-37AE3OM5.mjs → chunk-V4CUTCHS.mjs} +4 -4
  88. package/dist/{chunk-THVO2N47.mjs → chunk-VFH632TB.mjs} +9 -9
  89. package/dist/{chunk-3ERBUVHC.mjs → chunk-VJ3GC7W3.mjs} +95 -49
  90. package/dist/{chunk-V6XGXYCJ.mjs → chunk-VLELWBEW.mjs} +4 -4
  91. package/dist/{chunk-FEZKMUCF.mjs → chunk-WDTXHLYM.mjs} +1 -1
  92. package/dist/chunk-WUA546RX.mjs +129 -0
  93. package/dist/chunk-XHGISOX5.mjs +257 -0
  94. package/dist/chunk-XIY5DJXI.mjs +168 -0
  95. package/dist/{chunk-TOWTPLRC.mjs → chunk-XN37434W.mjs} +8 -8
  96. package/dist/{chunk-KLTACJ2G.mjs → chunk-XTWAJWCQ.mjs} +1 -1
  97. package/dist/chunk-Y24TXIFJ.mjs +518 -0
  98. package/dist/{chunk-DMXYRCHM.mjs → chunk-Y6UM3VTN.mjs} +4 -4
  99. package/dist/components/ui/about-you-form.js +1120 -0
  100. package/dist/components/ui/about-you-form.mjs +323 -0
  101. package/dist/components/ui/account-list-carousel.js +304 -0
  102. package/dist/components/ui/account-list-carousel.mjs +11 -0
  103. package/dist/components/ui/add-column-modal.js +1 -1
  104. package/dist/components/ui/add-column-modal.mjs +6 -6
  105. package/dist/components/ui/add-lead-modal.js +2 -2
  106. package/dist/components/ui/add-lead-modal.mjs +6 -6
  107. package/dist/components/ui/advisor-card.mjs +2 -2
  108. package/dist/components/ui/agent-evaluation-toast.js +299 -0
  109. package/dist/components/ui/agent-evaluation-toast.mjs +12 -0
  110. package/dist/components/ui/ai-assistant-drawer.mjs +5 -5
  111. package/dist/components/ui/ai-builder.js +3 -3
  112. package/dist/components/ui/ai-builder.mjs +5 -5
  113. package/dist/components/ui/ai-conversations.js +2 -2
  114. package/dist/components/ui/ai-conversations.mjs +11 -11
  115. package/dist/components/ui/alert-dialog.mjs +3 -3
  116. package/dist/components/ui/applicant-document-checklist.js +346 -0
  117. package/dist/components/ui/applicant-document-checklist.mjs +10 -0
  118. package/dist/components/ui/applicant-expenses-section.js +455 -0
  119. package/dist/components/ui/applicant-expenses-section.mjs +220 -0
  120. package/dist/components/ui/applicant-navigation-bar.js +309 -0
  121. package/dist/components/ui/applicant-navigation-bar.mjs +87 -0
  122. package/dist/components/ui/applicant-switcher.js +268 -0
  123. package/dist/components/ui/applicant-switcher.mjs +46 -0
  124. package/dist/components/ui/application-mobile-layout.js +88 -0
  125. package/dist/components/ui/application-mobile-layout.mjs +8 -0
  126. package/dist/components/ui/appointment-action-dialogs.js +1 -1
  127. package/dist/components/ui/appointment-action-dialogs.mjs +10 -10
  128. package/dist/components/ui/appointment-availability-settings.js +78 -31
  129. package/dist/components/ui/appointment-availability-settings.mjs +12 -10
  130. package/dist/components/ui/appointment-book-dialog.js +137 -58
  131. package/dist/components/ui/appointment-book-dialog.mjs +14 -14
  132. package/dist/components/ui/appointment-calendar-view.js +1 -1
  133. package/dist/components/ui/appointment-calendar-view.mjs +4 -4
  134. package/dist/components/ui/appointment-detail-sheet.js +38 -11
  135. package/dist/components/ui/appointment-detail-sheet.mjs +13 -13
  136. package/dist/components/ui/appointment-gmail-connect.mjs +2 -2
  137. package/dist/components/ui/appointment-time-slot-picker.mjs +2 -2
  138. package/dist/components/ui/appointment-upcoming-card.js +1 -1
  139. package/dist/components/ui/appointment-upcoming-card.mjs +10 -10
  140. package/dist/components/ui/asset-accordion.js +506 -0
  141. package/dist/components/ui/asset-accordion.mjs +202 -0
  142. package/dist/components/ui/assets-liabilities-side-card.js +328 -0
  143. package/dist/components/ui/assets-liabilities-side-card.mjs +127 -0
  144. package/dist/components/ui/auth-page-layout.js +3 -3
  145. package/dist/components/ui/auth-page-layout.mjs +1 -1
  146. package/dist/components/ui/backoffice-alert-history-chart.mjs +4 -4
  147. package/dist/components/ui/backoffice-alert-matching-chart.js +786 -0
  148. package/dist/components/ui/backoffice-alert-matching-chart.mjs +19 -0
  149. package/dist/components/ui/backoffice-alerts-chart.mjs +4 -4
  150. package/dist/components/ui/backoffice-connections-chart.mjs +4 -4
  151. package/dist/components/ui/backoffice-contact-history-chart.mjs +4 -4
  152. package/dist/components/ui/backoffice-contact-matching-chart.js +803 -0
  153. package/dist/components/ui/backoffice-contact-matching-chart.mjs +19 -0
  154. package/dist/components/ui/backoffice-signup-steps.js +1673 -0
  155. package/dist/components/ui/backoffice-signup-steps.mjs +36 -0
  156. package/dist/components/ui/bank-statement-document-table.js +467 -0
  157. package/dist/components/ui/bank-statement-document-table.mjs +12 -0
  158. package/dist/components/ui/bank-statement-generate-dialog.js +1517 -0
  159. package/dist/components/ui/bank-statement-generate-dialog.mjs +27 -0
  160. package/dist/components/ui/bank-statement-pdf-viewer.js +525 -0
  161. package/dist/components/ui/bank-statement-pdf-viewer.mjs +14 -0
  162. package/dist/components/ui/banking-accounts-connect.js +336 -0
  163. package/dist/components/ui/banking-accounts-connect.mjs +114 -0
  164. package/dist/components/ui/borrowing-capacity-atoms.js +382 -0
  165. package/dist/components/ui/borrowing-capacity-atoms.mjs +17 -0
  166. package/dist/components/ui/borrowing-capacity-card.js +835 -0
  167. package/dist/components/ui/borrowing-capacity-card.mjs +89 -0
  168. package/dist/components/ui/borrowing-capacity-line-chart.mjs +4 -4
  169. package/dist/components/ui/broker-info-panel.js +281 -0
  170. package/dist/components/ui/broker-info-panel.mjs +59 -0
  171. package/dist/components/ui/calculator-input-item.js +101 -0
  172. package/dist/components/ui/calculator-input-item.mjs +8 -0
  173. package/dist/components/ui/calculator-section.js +743 -0
  174. package/dist/components/ui/calculator-section.mjs +220 -0
  175. package/dist/components/ui/calendar.mjs +2 -2
  176. package/dist/components/ui/cash-balance-line-chart.mjs +5 -5
  177. package/dist/components/ui/cashflow-bar-chart.mjs +4 -4
  178. package/dist/components/ui/category-edit-dialog.js +737 -0
  179. package/dist/components/ui/category-edit-dialog.mjs +16 -0
  180. package/dist/components/ui/chat-widget.mjs +3 -3
  181. package/dist/components/ui/color-picker.mjs +4 -4
  182. package/dist/components/ui/connect-bank-step.js +511 -0
  183. package/dist/components/ui/connect-bank-step.mjs +287 -0
  184. package/dist/components/ui/contact-alert-dialog.js +1405 -0
  185. package/dist/components/ui/contact-alert-dialog.mjs +27 -0
  186. package/dist/components/ui/create-contact-modal.js +1028 -0
  187. package/dist/components/ui/create-contact-modal.mjs +21 -0
  188. package/dist/components/ui/csv-import-modal.js +583 -0
  189. package/dist/components/ui/csv-import-modal.mjs +14 -0
  190. package/dist/components/ui/currency-input.js +439 -0
  191. package/dist/components/ui/currency-input.mjs +13 -0
  192. package/dist/components/ui/dashboard-expense-categories.js +355 -0
  193. package/dist/components/ui/dashboard-expense-categories.mjs +186 -0
  194. package/dist/components/ui/dashboard-transactions-table.js +1083 -0
  195. package/dist/components/ui/dashboard-transactions-table.mjs +177 -0
  196. package/dist/components/ui/data-table.mjs +6 -6
  197. package/dist/components/ui/date-picker.mjs +6 -6
  198. package/dist/components/ui/debt-accordion.js +523 -0
  199. package/dist/components/ui/debt-accordion.mjs +219 -0
  200. package/dist/components/ui/delete-contact-component.js +479 -0
  201. package/dist/components/ui/delete-contact-component.mjs +14 -0
  202. package/dist/components/ui/dialog.js +1 -1
  203. package/dist/components/ui/dialog.mjs +3 -3
  204. package/dist/components/ui/document-checklist-template.mjs +4 -4
  205. package/dist/components/ui/drawer.mjs +3 -3
  206. package/dist/components/ui/dropdown-menu.mjs +3 -3
  207. package/dist/components/ui/dynamic-tabs.js +274 -0
  208. package/dist/components/ui/dynamic-tabs.mjs +116 -0
  209. package/dist/components/ui/editable-money-item.js +306 -0
  210. package/dist/components/ui/editable-money-item.mjs +12 -0
  211. package/dist/components/ui/expense-bar-chart.mjs +4 -4
  212. package/dist/components/ui/expense-detail-item.js +506 -0
  213. package/dist/components/ui/expense-detail-item.mjs +15 -0
  214. package/dist/components/ui/expense-work-details.js +1259 -0
  215. package/dist/components/ui/expense-work-details.mjs +175 -0
  216. package/dist/components/ui/field.mjs +2 -2
  217. package/dist/components/ui/file-preview-dialog.js +704 -0
  218. package/dist/components/ui/file-preview-dialog.mjs +17 -0
  219. package/dist/components/ui/financial-cards.mjs +2 -2
  220. package/dist/components/ui/financial-drawers.js +1 -1
  221. package/dist/components/ui/financial-drawers.mjs +5 -5
  222. package/dist/components/ui/financial-sections.mjs +4 -4
  223. package/dist/components/ui/form-primitives.mjs +2 -2
  224. package/dist/components/ui/frontend-signup-steps.js +1239 -0
  225. package/dist/components/ui/frontend-signup-steps.mjs +38 -0
  226. package/dist/components/ui/income-bar-chart.mjs +4 -4
  227. package/dist/components/ui/income-sources-card.js +269 -0
  228. package/dist/components/ui/income-sources-card.mjs +100 -0
  229. package/dist/components/ui/income-summary-component.js +361 -0
  230. package/dist/components/ui/income-summary-component.mjs +84 -0
  231. package/dist/components/ui/income-work-details.js +1663 -0
  232. package/dist/components/ui/income-work-details.mjs +28 -0
  233. package/dist/components/ui/incoming-outgoings-card.js +218 -0
  234. package/dist/components/ui/incoming-outgoings-card.mjs +82 -0
  235. package/dist/components/ui/interest-rate-input.js +442 -0
  236. package/dist/components/ui/interest-rate-input.mjs +90 -0
  237. package/dist/components/ui/interest-rate-section.js +337 -0
  238. package/dist/components/ui/interest-rate-section.mjs +84 -0
  239. package/dist/components/ui/interest-rate-used.js +202 -0
  240. package/dist/components/ui/interest-rate-used.mjs +62 -0
  241. package/dist/components/ui/kanban-column.js +338 -160
  242. package/dist/components/ui/kanban-column.mjs +13 -11
  243. package/dist/components/ui/loan-applicant-information.js +336 -0
  244. package/dist/components/ui/loan-applicant-information.mjs +59 -0
  245. package/dist/components/ui/loan-applicant-invite.js +319 -0
  246. package/dist/components/ui/loan-applicant-invite.mjs +68 -0
  247. package/dist/components/ui/loan-application-badge.js +236 -0
  248. package/dist/components/ui/loan-application-badge.mjs +10 -0
  249. package/dist/components/ui/loan-application-cards.js +356 -0
  250. package/dist/components/ui/loan-application-cards.mjs +110 -0
  251. package/dist/components/ui/loan-entry-shell.js +104 -0
  252. package/dist/components/ui/loan-entry-shell.mjs +8 -0
  253. package/dist/components/ui/loan-financials.js +410 -0
  254. package/dist/components/ui/loan-financials.mjs +76 -0
  255. package/dist/components/ui/loan-option-card.js +102 -0
  256. package/dist/components/ui/loan-option-card.mjs +41 -0
  257. package/dist/components/ui/loan-option-group.js +288 -0
  258. package/dist/components/ui/loan-option-group.mjs +10 -0
  259. package/dist/components/ui/loan-steps.js +1121 -0
  260. package/dist/components/ui/loan-steps.mjs +509 -0
  261. package/dist/components/ui/loan-wizard-shell.js +452 -0
  262. package/dist/components/ui/loan-wizard-shell.mjs +11 -0
  263. package/dist/components/ui/money-input-with-slider.js +210 -0
  264. package/dist/components/ui/money-input-with-slider.mjs +10 -0
  265. package/dist/components/ui/money-item-with-color-indicator.js +314 -0
  266. package/dist/components/ui/money-item-with-color-indicator.mjs +20 -0
  267. package/dist/components/ui/opportunity-card.js +235 -97
  268. package/dist/components/ui/opportunity-card.mjs +11 -9
  269. package/dist/components/ui/opportunity-edit-modals.js +1 -1
  270. package/dist/components/ui/opportunity-edit-modals.mjs +15 -15
  271. package/dist/components/ui/opportunity-summary-tab.js +1 -1
  272. package/dist/components/ui/opportunity-summary-tab.mjs +19 -19
  273. package/dist/components/ui/pagination.mjs +4 -4
  274. package/dist/components/ui/password-strength-tooltip.mjs +4 -4
  275. package/dist/components/ui/pipeline-board.js +358 -176
  276. package/dist/components/ui/pipeline-board.mjs +16 -14
  277. package/dist/components/ui/pipeline-chart.mjs +3 -3
  278. package/dist/components/ui/pipeline-dialogs.js +1 -1
  279. package/dist/components/ui/pipeline-dialogs.mjs +9 -9
  280. package/dist/components/ui/pipeline-primitives.js +75 -8
  281. package/dist/components/ui/pipeline-primitives.mjs +3 -2
  282. package/dist/components/ui/popover.mjs +3 -3
  283. package/dist/components/ui/property-asset-card.js +428 -0
  284. package/dist/components/ui/property-asset-card.mjs +156 -0
  285. package/dist/components/ui/property-cashflow-doughnut-chart.mjs +4 -4
  286. package/dist/components/ui/property-debt-equity-doughnut-chart.mjs +4 -4
  287. package/dist/components/ui/property-list-carousel.js +295 -0
  288. package/dist/components/ui/property-list-carousel.mjs +11 -0
  289. package/dist/components/ui/property-mobile-estimate-line-chart.mjs +4 -4
  290. package/dist/components/ui/property-report-dialog.js +1148 -0
  291. package/dist/components/ui/property-report-dialog.mjs +25 -0
  292. package/dist/components/ui/resource-center.js +748 -0
  293. package/dist/components/ui/resource-center.mjs +24 -0
  294. package/dist/components/ui/review-alerts-dialog.js +569 -0
  295. package/dist/components/ui/review-alerts-dialog.mjs +15 -0
  296. package/dist/components/ui/savings-goal-modal.js +1148 -0
  297. package/dist/components/ui/savings-goal-modal.mjs +160 -0
  298. package/dist/components/ui/scenario-drawer.js +791 -0
  299. package/dist/components/ui/scenario-drawer.mjs +294 -0
  300. package/dist/components/ui/scenario-item.js +256 -0
  301. package/dist/components/ui/scenario-item.mjs +11 -0
  302. package/dist/components/ui/scenario-list.js +507 -0
  303. package/dist/components/ui/scenario-list.mjs +100 -0
  304. package/dist/components/ui/select.mjs +3 -3
  305. package/dist/components/ui/share-details-dialog.js +636 -0
  306. package/dist/components/ui/share-details-dialog.mjs +19 -0
  307. package/dist/components/ui/sheet.mjs +3 -3
  308. package/dist/components/ui/sidebar-nav.mjs +5 -5
  309. package/dist/components/ui/signup-form-primitives.js +770 -0
  310. package/dist/components/ui/signup-form-primitives.mjs +25 -0
  311. package/dist/components/ui/signup-shell.js +338 -0
  312. package/dist/components/ui/signup-shell.mjs +13 -0
  313. package/dist/components/ui/stage-timeline.js +103 -33
  314. package/dist/components/ui/stage-timeline.mjs +5 -4
  315. package/dist/components/ui/submission-confirmation-card.js +284 -0
  316. package/dist/components/ui/submission-confirmation-card.mjs +62 -0
  317. package/dist/components/ui/tooltip.mjs +3 -3
  318. package/dist/components/ui/top-three-product.js +374 -0
  319. package/dist/components/ui/top-three-product.mjs +129 -0
  320. package/dist/components/ui/transactions-expense-categories-doughnut-chart.mjs +4 -4
  321. package/dist/components/ui/transactions-income-expense-bar-chart.mjs +5 -5
  322. package/dist/components/ui/transactions-liabilities-breakdown-doughnut-chart.mjs +4 -4
  323. package/dist/components/ui/transactions-summary-block.js +95 -0
  324. package/dist/components/ui/transactions-summary-block.mjs +34 -0
  325. package/dist/components/ui/two-fa-setup-form.mjs +3 -3
  326. package/dist/index.js +9430 -4573
  327. package/dist/index.mjs +404 -251
  328. package/dist/lib/colors.js +6 -0
  329. package/dist/lib/colors.mjs +3 -1
  330. package/dist/lib/theme-provider.mjs +2 -2
  331. package/dist/styles.css +1 -1
  332. package/package.json +367 -3
  333. package/src/components/index.tsx +223 -0
  334. package/src/components/ui/about-you-form.tsx +397 -0
  335. package/src/components/ui/account-list-carousel.tsx +87 -0
  336. package/src/components/ui/add-lead-modal.tsx +1 -1
  337. package/src/components/ui/agent-evaluation-toast.tsx +191 -0
  338. package/src/components/ui/ai-builder.tsx +3 -5
  339. package/src/components/ui/ai-conversations.tsx +1 -1
  340. package/src/components/ui/applicant-document-checklist.tsx +175 -0
  341. package/src/components/ui/applicant-expenses-section.tsx +260 -0
  342. package/src/components/ui/applicant-navigation-bar.tsx +104 -0
  343. package/src/components/ui/applicant-switcher.tsx +54 -0
  344. package/src/components/ui/application-mobile-layout.tsx +34 -0
  345. package/src/components/ui/appointment-availability-settings.tsx +115 -23
  346. package/src/components/ui/appointment-book-dialog.tsx +406 -259
  347. package/src/components/ui/appointment-calendar-view.tsx +4 -1
  348. package/src/components/ui/appointment-detail-sheet.tsx +59 -24
  349. package/src/components/ui/appointment-time-slot-picker.tsx +5 -1
  350. package/src/components/ui/asset-accordion.tsx +241 -0
  351. package/src/components/ui/assets-liabilities-side-card.tsx +157 -0
  352. package/src/components/ui/auth-page-layout.tsx +3 -3
  353. package/src/components/ui/backoffice-alert-matching-chart.tsx +320 -0
  354. package/src/components/ui/backoffice-contact-matching-chart.tsx +341 -0
  355. package/src/components/ui/backoffice-signup-steps.tsx +615 -0
  356. package/src/components/ui/bank-statement-document-table.tsx +222 -0
  357. package/src/components/ui/bank-statement-generate-dialog.tsx +435 -0
  358. package/src/components/ui/bank-statement-pdf-viewer.tsx +241 -0
  359. package/src/components/ui/banking-accounts-connect.tsx +187 -0
  360. package/src/components/ui/borrowing-capacity-atoms.tsx +228 -0
  361. package/src/components/ui/borrowing-capacity-card.tsx +155 -0
  362. package/src/components/ui/broker-info-panel.tsx +94 -0
  363. package/src/components/ui/calculator-input-item.tsx +49 -0
  364. package/src/components/ui/calculator-section.tsx +275 -0
  365. package/src/components/ui/category-edit-dialog.tsx +300 -0
  366. package/src/components/ui/connect-bank-step.tsx +379 -0
  367. package/src/components/ui/contact-alert-dialog.tsx +710 -0
  368. package/src/components/ui/create-contact-modal.tsx +237 -0
  369. package/src/components/ui/csv-import-modal.tsx +153 -0
  370. package/src/components/ui/currency-input.tsx +104 -0
  371. package/src/components/ui/dashboard-expense-categories.tsx +262 -0
  372. package/src/components/ui/dashboard-transactions-table.tsx +241 -0
  373. package/src/components/ui/debt-accordion.tsx +254 -0
  374. package/src/components/ui/delete-contact-component.tsx +87 -0
  375. package/src/components/ui/dialog.tsx +2 -2
  376. package/src/components/ui/dynamic-tabs.tsx +149 -0
  377. package/src/components/ui/editable-money-item.tsx +176 -0
  378. package/src/components/ui/expense-detail-item.tsx +216 -0
  379. package/src/components/ui/expense-work-details.tsx +229 -0
  380. package/src/components/ui/file-preview-dialog.tsx +292 -0
  381. package/src/components/ui/financial-drawers.tsx +1 -1
  382. package/src/components/ui/frontend-signup-steps.tsx +548 -0
  383. package/src/components/ui/income-sources-card.tsx +143 -0
  384. package/src/components/ui/income-summary-component.tsx +120 -0
  385. package/src/components/ui/income-work-details.tsx +429 -0
  386. package/src/components/ui/incoming-outgoings-card.tsx +111 -0
  387. package/src/components/ui/interest-rate-input.tsx +111 -0
  388. package/src/components/ui/interest-rate-section.tsx +158 -0
  389. package/src/components/ui/interest-rate-used.tsx +82 -0
  390. package/src/components/ui/kanban-column.tsx +53 -2
  391. package/src/components/ui/loan-applicant-information.tsx +64 -0
  392. package/src/components/ui/loan-applicant-invite.tsx +67 -0
  393. package/src/components/ui/loan-application-badge.tsx +70 -0
  394. package/src/components/ui/loan-application-cards.tsx +152 -0
  395. package/src/components/ui/loan-entry-shell.tsx +86 -0
  396. package/src/components/ui/loan-financials.tsx +77 -0
  397. package/src/components/ui/loan-option-card.tsx +62 -0
  398. package/src/components/ui/loan-option-group.tsx +106 -0
  399. package/src/components/ui/loan-steps.tsx +630 -0
  400. package/src/components/ui/loan-wizard-shell.tsx +235 -0
  401. package/src/components/ui/money-input-with-slider.tsx +77 -0
  402. package/src/components/ui/money-item-with-color-indicator.tsx +30 -0
  403. package/src/components/ui/opportunity-card.tsx +46 -18
  404. package/src/components/ui/pipeline-board.tsx +13 -0
  405. package/src/components/ui/pipeline-primitives.tsx +28 -0
  406. package/src/components/ui/property-asset-card.tsx +221 -0
  407. package/src/components/ui/property-list-carousel.tsx +73 -0
  408. package/src/components/ui/property-report-dialog.tsx +355 -0
  409. package/src/components/ui/resource-center.tsx +539 -0
  410. package/src/components/ui/review-alerts-dialog.tsx +163 -0
  411. package/src/components/ui/savings-goal-modal.tsx +169 -0
  412. package/src/components/ui/scenario-drawer.tsx +358 -0
  413. package/src/components/ui/scenario-item.tsx +141 -0
  414. package/src/components/ui/scenario-list.tsx +150 -0
  415. package/src/components/ui/share-details-dialog.tsx +238 -0
  416. package/src/components/ui/signup-form-primitives.tsx +212 -0
  417. package/src/components/ui/signup-shell.tsx +180 -0
  418. package/src/components/ui/stage-timeline.tsx +11 -0
  419. package/src/components/ui/submission-confirmation-card.tsx +68 -0
  420. package/src/components/ui/top-three-product.tsx +207 -0
  421. package/src/components/ui/transactions-summary-block.tsx +59 -0
  422. package/src/lib/colors.ts +12 -0
  423. package/src/lib/format-date.ts +2 -2
  424. package/src/styles/styles-css.ts +1 -1
  425. package/tsup.config.ts +77 -1
  426. package/dist/{chunk-5VOTTIXF.mjs → chunk-FRT3S72S.mjs} +3 -3
  427. package/dist/{chunk-7BTFGCFC.mjs → chunk-MUV4EGDW.mjs} +3 -3
  428. package/dist/{chunk-57ZXILTS.mjs → chunk-MXP2RX2V.mjs} +3 -3
  429. package/dist/{chunk-ZKWXDQDG.mjs → chunk-VCDGLN25.mjs} +3 -3
  430. package/dist/{chunk-FLL633WS.mjs → chunk-ZXEUBBHJ.mjs} +3 -3
@@ -0,0 +1,221 @@
1
+ import { Building2 } from "lucide-react";
2
+ import { cn } from "@/lib/utils";
3
+ import { Badge } from "@/components/ui/badge";
4
+ import {
5
+ Accordion,
6
+ AccordionContent,
7
+ AccordionItem,
8
+ AccordionTrigger,
9
+ } from "@/components/ui/accordion";
10
+ import { formatCurrency } from "@/lib/format-currency";
11
+
12
+ // ─── Types ────────────────────────────────────────────────────────────────────
13
+
14
+ export type PropertyMortgage = {
15
+ id: string;
16
+ /** Display label e.g. "Mortgage" */
17
+ label: string;
18
+ /** Loan type shown as a badge e.g. "Home Loan", "Investment Loan" */
19
+ type: string;
20
+ /** Monthly repayment shown in the accordion header */
21
+ monthlyRepayment: number;
22
+ /** Outstanding loan balance */
23
+ loanAmount: number;
24
+ /** Monthly repayment shown in Loan Details */
25
+ repaymentAmount: number;
26
+ /** Annual interest rate (%) */
27
+ interestRate: number;
28
+ };
29
+
30
+ export type PropertyAssetCardProps = {
31
+ /** Full property address */
32
+ address: string;
33
+ /** Asset category label shown below the address */
34
+ assetType?: string;
35
+ /** URL for the lending institution's logo — falls back to a building icon */
36
+ institutionLogoUrl?: string;
37
+ /** Current estimated market value */
38
+ estimatedValue: number;
39
+ /** Loan-to-value ratio (0–100) */
40
+ lvr?: number;
41
+ /** Net equity in dollars (estimatedValue − totalOwing) */
42
+ netEquity?: number;
43
+ /** Linked mortgage records */
44
+ mortgages?: PropertyMortgage[];
45
+ className?: string;
46
+ };
47
+
48
+ // ─── Constants ────────────────────────────────────────────────────────────────
49
+
50
+ const EMPTY_MORTGAGES: PropertyMortgage[] = [];
51
+
52
+ // ─── Component ────────────────────────────────────────────────────────────────
53
+
54
+ /**
55
+ * PropertyAssetCard — summary card for a single property asset in the loan
56
+ * wizard Assets tab.
57
+ *
58
+ * Shows: institution logo, address, estimated value, interest rate + LVR stats,
59
+ * net equity highlight, and an expandable mortgage accordion with Loan Details
60
+ * and Property Statistics sub-sections.
61
+ *
62
+ * Figma: WealthX-Backoffice---Mobile-App — node 17418:41358
63
+ */
64
+ export function PropertyAssetCard({
65
+ address,
66
+ assetType = "Property",
67
+ institutionLogoUrl,
68
+ estimatedValue,
69
+ lvr,
70
+ netEquity,
71
+ mortgages = EMPTY_MORTGAGES,
72
+ className,
73
+ }: PropertyAssetCardProps) {
74
+ const primaryRate = mortgages[0]?.interestRate;
75
+
76
+ return (
77
+ <div
78
+ className={cn(
79
+ "flex flex-col gap-4 border border-border p-4 font-sans",
80
+ className,
81
+ )}
82
+ >
83
+ <div className="flex items-start gap-3">
84
+ <div className="flex size-14 shrink-0 items-center justify-center bg-muted">
85
+ {institutionLogoUrl ? (
86
+ <img
87
+ src={institutionLogoUrl}
88
+ alt=""
89
+ className="size-full object-contain"
90
+ />
91
+ ) : (
92
+ <Building2
93
+ className="size-6 text-muted-foreground"
94
+ aria-hidden="true"
95
+ />
96
+ )}
97
+ </div>
98
+
99
+ <div className="flex min-w-0 flex-1 items-start justify-between gap-2">
100
+ <div className="flex min-w-0 flex-col gap-0.5">
101
+ <span className="text-body-small font-semibold text-foreground">
102
+ {address}
103
+ </span>
104
+ <span className="text-body-small text-muted-foreground">
105
+ {assetType}
106
+ </span>
107
+ </div>
108
+ <span className="shrink-0 text-body-small font-semibold text-foreground">
109
+ {formatCurrency(estimatedValue)}
110
+ </span>
111
+ </div>
112
+ </div>
113
+
114
+ {(primaryRate != null || lvr != null) && (
115
+ <div className="flex gap-6 text-xs">
116
+ {primaryRate != null && (
117
+ <span className="text-muted-foreground">
118
+ Interest Rate:{" "}
119
+ <span className="font-semibold text-foreground">
120
+ {primaryRate}%
121
+ </span>
122
+ </span>
123
+ )}
124
+ {lvr != null && (
125
+ <span className="text-muted-foreground">
126
+ LVR <span className="font-semibold text-foreground">{lvr}%</span>
127
+ </span>
128
+ )}
129
+ </div>
130
+ )}
131
+
132
+ <div className="border-t border-border" />
133
+
134
+ {netEquity != null && (
135
+ <div className="flex items-center justify-between border border-primary/40 bg-primary/10 px-4 py-3">
136
+ <span className="text-body-small font-semibold text-foreground">
137
+ Net Equity
138
+ </span>
139
+ <span className="text-body-small font-semibold text-foreground">
140
+ {formatCurrency(netEquity)}
141
+ </span>
142
+ </div>
143
+ )}
144
+
145
+ {mortgages.length > 0 && (
146
+ <Accordion type="multiple">
147
+ {mortgages.map((mortgage) => (
148
+ <AccordionItem key={mortgage.id} value={mortgage.id}>
149
+ <AccordionTrigger>
150
+ <div className="flex flex-1 items-center justify-between pr-2">
151
+ <div className="flex flex-col gap-1.5 items-start">
152
+ <span className="text-body-small font-semibold text-foreground">
153
+ {mortgage.label}
154
+ </span>
155
+ <Badge variant="secondary">{mortgage.type}</Badge>
156
+ </div>
157
+ <span className="text-body-small font-semibold text-foreground">
158
+ {formatCurrency(mortgage.monthlyRepayment)}
159
+ </span>
160
+ </div>
161
+ </AccordionTrigger>
162
+
163
+ <AccordionContent>
164
+ <div className="flex flex-col gap-2 pt-1">
165
+ <div className="flex flex-col gap-2 bg-muted/50 p-4">
166
+ <span className="text-body-small font-semibold text-foreground">
167
+ Loan Details
168
+ </span>
169
+ <DetailRow
170
+ label="Loan Amount"
171
+ value={formatCurrency(mortgage.loanAmount)}
172
+ />
173
+ <DetailRow
174
+ label="Repayment Amount"
175
+ value={formatCurrency(mortgage.repaymentAmount)}
176
+ />
177
+ <DetailRow
178
+ label="Interest Rate"
179
+ value={`${mortgage.interestRate}%`}
180
+ />
181
+ </div>
182
+
183
+ <div className="flex flex-col gap-2 border border-primary/40 bg-primary/10 p-4">
184
+ <span className="text-body-small font-semibold text-foreground">
185
+ Property Statistics
186
+ </span>
187
+ <DetailRow
188
+ label="Property Estimate"
189
+ value={formatCurrency(estimatedValue)}
190
+ />
191
+ {lvr != null && <DetailRow label="LVR" value={`${lvr}%`} />}
192
+ {netEquity != null && (
193
+ <>
194
+ <div className="border-t border-primary/40" />
195
+ <DetailRow
196
+ label="Equity Available"
197
+ value={formatCurrency(netEquity)}
198
+ />
199
+ </>
200
+ )}
201
+ </div>
202
+ </div>
203
+ </AccordionContent>
204
+ </AccordionItem>
205
+ ))}
206
+ </Accordion>
207
+ )}
208
+ </div>
209
+ );
210
+ }
211
+
212
+ // ─── Internal helpers ─────────────────────────────────────────────────────────
213
+
214
+ function DetailRow({ label, value }: { label: string; value: string }) {
215
+ return (
216
+ <div className="flex items-center justify-between">
217
+ <span className="text-xs text-muted-foreground">{label}</span>
218
+ <span className="text-xs font-semibold text-foreground">{value}</span>
219
+ </div>
220
+ );
221
+ }
@@ -0,0 +1,73 @@
1
+ import React from "react";
2
+ import { cn } from "@/lib/utils";
3
+ import { formatCurrency } from "@/lib/format-currency";
4
+ import { Button } from "./button";
5
+ import { Plus } from "lucide-react";
6
+
7
+ export type PropertyCarouselType = "homeLoan" | "property";
8
+
9
+ export interface PropertyCarouselItem {
10
+ id: string;
11
+ address: string;
12
+ /** Estimated value or equity */
13
+ value: number;
14
+ /** Linked loan balance, if any */
15
+ loanBalance?: number;
16
+ }
17
+
18
+ export interface PropertyListCarouselProps {
19
+ properties: PropertyCarouselItem[];
20
+ type: PropertyCarouselType;
21
+ /** When provided, shows an "Add Property" button at the end (property type only) */
22
+ onAddProperty?: () => void;
23
+ className?: string;
24
+ }
25
+
26
+ function PropertyCard({ item }: { item: PropertyCarouselItem }) {
27
+ return (
28
+ <div className="flex shrink-0 flex-col gap-1.5 border border-border p-3 w-44">
29
+ <p className="text-xs text-muted-foreground truncate">{item.address}</p>
30
+ <p className="text-sm font-semibold tabular-nums text-foreground">
31
+ {formatCurrency(item.value)}
32
+ </p>
33
+ {item.loanBalance !== undefined && (
34
+ <p className="text-xs text-muted-foreground tabular-nums">
35
+ Loan: {formatCurrency(item.loanBalance)}
36
+ </p>
37
+ )}
38
+ </div>
39
+ );
40
+ }
41
+
42
+ export function PropertyListCarousel({
43
+ properties,
44
+ type,
45
+ onAddProperty,
46
+ className,
47
+ }: PropertyListCarouselProps) {
48
+ const showAddButton = type === "property" && onAddProperty;
49
+
50
+ return (
51
+ <div
52
+ className={cn(
53
+ "flex gap-2 overflow-x-auto pb-1 scrollbar-none",
54
+ className,
55
+ )}
56
+ >
57
+ {properties.map((property) => (
58
+ <PropertyCard key={property.id} item={property} />
59
+ ))}
60
+
61
+ {showAddButton && (
62
+ <Button
63
+ variant="outline"
64
+ onClick={onAddProperty}
65
+ className="shrink-0 h-auto w-44 flex-col gap-1.5 border-dashed p-3 text-muted-foreground"
66
+ >
67
+ <Plus className="h-4 w-4" />
68
+ <span className="text-xs">Add Property</span>
69
+ </Button>
70
+ )}
71
+ </div>
72
+ );
73
+ }
@@ -0,0 +1,355 @@
1
+ import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { Trash2, Plus } from "lucide-react";
3
+ import { cn } from "@/lib/utils";
4
+ import { formatCurrency } from "@/lib/format-currency";
5
+ import { Button } from "@/components/ui/button";
6
+ import { Checkbox } from "@/components/ui/checkbox";
7
+ import {
8
+ Dialog,
9
+ DialogContent,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ } from "@/components/ui/dialog";
14
+ import { Field, FieldLabel } from "@/components/ui/field";
15
+ import {
16
+ AddressAutocomplete,
17
+ type AddressOption,
18
+ } from "@/components/ui/form-primitives";
19
+ import { Input } from "@/components/ui/input";
20
+ import { Separator } from "@/components/ui/separator";
21
+ import { Spinner } from "@/components/ui/spinner";
22
+ import {
23
+ Table,
24
+ TableBody,
25
+ TableCell,
26
+ TableHead,
27
+ TableHeader,
28
+ TableRow,
29
+ } from "@/components/ui/table";
30
+
31
+ /**
32
+ * PropertyReportDialog — WealthX DS (L4 Template)
33
+ *
34
+ * Dialog for generating a property valuation report from the scenario's
35
+ * linked properties. Opened from the Bank Statement tab of
36
+ * `OpportunityDetailsDrawer` when the user selects "Property Report" and
37
+ * clicks "Generate".
38
+ *
39
+ * Internal state:
40
+ * - Report name (Input)
41
+ * - Manually added properties (via AddressAutocomplete + Add button)
42
+ * - Selected property IDs (Table with Checkboxes)
43
+ *
44
+ * Data handed in via props (consumer owns fetching):
45
+ * - `properties` — pre-loaded properties from the scenario (API list)
46
+ * - `isLoadingProperties` — spinner while fetching
47
+ * - `searchResults` — address search results driven by `onSearchQueryChange`
48
+ *
49
+ * Layer: L4 Template
50
+ */
51
+
52
+ // ---------------------------------------------------------------------------
53
+ // Types
54
+ // ---------------------------------------------------------------------------
55
+
56
+ export interface PropertyItem {
57
+ id: string;
58
+ address?: string;
59
+ propertyType?: string;
60
+ /** Estimated value in dollars. */
61
+ estimateValue?: number;
62
+ }
63
+
64
+ export interface PropertySearchResult {
65
+ /** Unique property identifier returned by the address search service. */
66
+ id: string;
67
+ /** Full address string shown in the dropdown. */
68
+ address: string;
69
+ }
70
+
71
+ export interface PropertyReportPayload {
72
+ reportName: string;
73
+ selectedPropertyIds: string[];
74
+ }
75
+
76
+ export interface PropertyReportDialogProps {
77
+ open: boolean;
78
+ onClose: () => void;
79
+ /**
80
+ * Called when the user clicks Generate (only when form is valid).
81
+ * Consumer is responsible for the actual API call.
82
+ */
83
+ onSubmit: (payload: PropertyReportPayload) => void;
84
+ /** Pre-loaded properties from the scenario's loan data. */
85
+ properties: PropertyItem[];
86
+ /** Provide `true` while the consumer is fetching the scenario's properties. */
87
+ isLoadingProperties?: boolean;
88
+ /**
89
+ * Address search results for the autocomplete dropdown.
90
+ * Consumer debounces and fetches when `onSearchQueryChange` fires.
91
+ */
92
+ searchResults?: PropertySearchResult[];
93
+ /**
94
+ * Called when the user types in the address search input (debounce externally).
95
+ * Pass an empty string when the query is cleared.
96
+ */
97
+ onSearchQueryChange?: (query: string) => void;
98
+ /** Show a loading indicator on the Generate button while the API call is in flight. */
99
+ isLoading?: boolean;
100
+ className?: string;
101
+ }
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // PropertyReportDialog
105
+ // ---------------------------------------------------------------------------
106
+
107
+ export function PropertyReportDialog({
108
+ open,
109
+ onClose,
110
+ onSubmit,
111
+ properties,
112
+ isLoadingProperties = false,
113
+ searchResults = [],
114
+ onSearchQueryChange,
115
+ isLoading = false,
116
+ className,
117
+ }: PropertyReportDialogProps) {
118
+ const [reportName, setReportName] = useState("Property Report 1");
119
+ const [selectedPropertyIds, setSelectedPropertyIds] = useState<string[]>([]);
120
+
121
+ // Properties added manually via the address search (not in the API list)
122
+ const [manualProperties, setManualProperties] = useState<PropertyItem[]>([]);
123
+
124
+ // Address autocomplete state
125
+ const [addressInputValue, setAddressInputValue] = useState("");
126
+ const [selectedSuggestion, setSelectedSuggestion] =
127
+ useState<PropertySearchResult | null>(null);
128
+
129
+ // Convert searchResults → AddressOption[] for AddressAutocomplete
130
+ const addressOptions = useMemo<AddressOption[]>(
131
+ () => searchResults.map((r) => ({ id: r.id, label: r.address })),
132
+ [searchResults],
133
+ );
134
+
135
+ // Reset form whenever the dialog opens
136
+ useEffect(() => {
137
+ if (!open) return;
138
+ setReportName("Property Report 1");
139
+ setSelectedPropertyIds([]);
140
+ setManualProperties([]);
141
+ setAddressInputValue("");
142
+ setSelectedSuggestion(null);
143
+ onSearchQueryChange?.("");
144
+ }, [open]); // eslint-disable-line react-hooks/exhaustive-deps
145
+
146
+ // Combined list shown in the table
147
+ const allProperties = useMemo<PropertyItem[]>(
148
+ () => [...properties, ...manualProperties],
149
+ [properties, manualProperties],
150
+ );
151
+
152
+ // ── Property selection ───────────────────────────────────────────────────
153
+
154
+ const areAllSelected =
155
+ allProperties.length > 0 &&
156
+ selectedPropertyIds.length === allProperties.length;
157
+ const isSomeSelected = selectedPropertyIds.length > 0 && !areAllSelected;
158
+
159
+ const handleToggleProperty = (id: string) => {
160
+ setSelectedPropertyIds((prev) =>
161
+ prev.includes(id) ? prev.filter((x) => x !== id) : [...prev, id],
162
+ );
163
+ };
164
+
165
+ const handleToggleAll = () => {
166
+ if (areAllSelected) {
167
+ setSelectedPropertyIds([]);
168
+ } else {
169
+ setSelectedPropertyIds(allProperties.map((p) => p.id));
170
+ }
171
+ };
172
+
173
+ // ── Address search & manual add ──────────────────────────────────────────
174
+
175
+ const handleAddProperty = useCallback(() => {
176
+ if (!selectedSuggestion) return;
177
+ const { id, address } = selectedSuggestion;
178
+
179
+ const alreadyExists = allProperties.some((p) => p.id === id);
180
+ if (alreadyExists) return; // silently skip (button is disabled when already added)
181
+
182
+ setManualProperties((prev) => [...prev, { id, address }]);
183
+ setSelectedSuggestion(null);
184
+ setAddressInputValue("");
185
+ onSearchQueryChange?.("");
186
+ }, [selectedSuggestion, allProperties, onSearchQueryChange]);
187
+
188
+ const handleRemoveManual = useCallback((id: string) => {
189
+ setManualProperties((prev) => prev.filter((p) => p.id !== id));
190
+ setSelectedPropertyIds((prev) => prev.filter((x) => x !== id));
191
+ }, []);
192
+
193
+ const isManual = (id: string) => manualProperties.some((p) => p.id === id);
194
+
195
+ const isAddDisabled =
196
+ !selectedSuggestion ||
197
+ allProperties.some((p) => p.id === selectedSuggestion.id);
198
+
199
+ // ── Submit guard ─────────────────────────────────────────────────────────
200
+
201
+ const isSubmitDisabled =
202
+ !reportName.trim() || selectedPropertyIds.length === 0;
203
+
204
+ const handleSubmit = () => {
205
+ if (isSubmitDisabled) return;
206
+ onSubmit({ reportName, selectedPropertyIds });
207
+ };
208
+
209
+ // ── Render ───────────────────────────────────────────────────────────────
210
+
211
+ return (
212
+ <Dialog open={open} onOpenChange={(o) => !o && onClose()}>
213
+ <DialogContent
214
+ size="auto"
215
+ className={cn(className)}
216
+ data-slot="property-report-dialog"
217
+ >
218
+ <DialogHeader>
219
+ <DialogTitle>Property Report</DialogTitle>
220
+ </DialogHeader>
221
+
222
+ <Separator />
223
+
224
+ <div className="flex flex-col gap-4 pt-1">
225
+ {/* Report name */}
226
+ <Field>
227
+ <FieldLabel>Name</FieldLabel>
228
+ <Input
229
+ value={reportName}
230
+ onChange={(e) => setReportName(e.target.value)}
231
+ placeholder="Property Report 1"
232
+ />
233
+ </Field>
234
+
235
+ {/* Address search + Add button */}
236
+ <div className="flex items-end gap-2">
237
+ <Field className="flex-1">
238
+ <FieldLabel>Search property</FieldLabel>
239
+ <AddressAutocomplete
240
+ value={addressInputValue}
241
+ suggestions={addressOptions}
242
+ placeholder="Start typing an address…"
243
+ onValueChange={(v) => {
244
+ setAddressInputValue(v);
245
+ setSelectedSuggestion(null);
246
+ onSearchQueryChange?.(v);
247
+ }}
248
+ onSelect={(opt) => {
249
+ setSelectedSuggestion({ id: opt.id, address: opt.label });
250
+ }}
251
+ />
252
+ </Field>
253
+ <Button
254
+ variant="outline"
255
+ onClick={handleAddProperty}
256
+ disabled={isAddDisabled}
257
+ >
258
+ <Plus className="size-4" />
259
+ Add
260
+ </Button>
261
+ </div>
262
+
263
+ {/* Properties table */}
264
+ <div>
265
+ {isLoadingProperties ? (
266
+ <div className="flex items-center justify-center p-6">
267
+ <Spinner size="lg" />
268
+ </div>
269
+ ) : allProperties.length === 0 ? (
270
+ <p className="py-4 text-center text-body-medium text-muted-foreground">
271
+ No properties found. Use the search above to add properties.
272
+ </p>
273
+ ) : (
274
+ <Table>
275
+ <TableHeader>
276
+ <TableRow>
277
+ <TableHead className="w-10">
278
+ <Checkbox
279
+ checked={areAllSelected}
280
+ indeterminate={isSomeSelected}
281
+ onCheckedChange={handleToggleAll}
282
+ aria-label="Select all properties"
283
+ />
284
+ </TableHead>
285
+ <TableHead>Address</TableHead>
286
+ <TableHead>Property Type</TableHead>
287
+ <TableHead>Estimate</TableHead>
288
+ <TableHead className="w-10" />
289
+ </TableRow>
290
+ </TableHeader>
291
+ <TableBody>
292
+ {allProperties.map((property) => (
293
+ <TableRow key={property.id}>
294
+ <TableCell>
295
+ <Checkbox
296
+ checked={selectedPropertyIds.includes(property.id)}
297
+ onCheckedChange={() =>
298
+ handleToggleProperty(property.id)
299
+ }
300
+ aria-label={`Select ${property.address ?? property.id}`}
301
+ />
302
+ </TableCell>
303
+ <TableCell>
304
+ <span className="text-body-medium font-semibold">
305
+ {property.address ?? "—"}
306
+ </span>
307
+ </TableCell>
308
+ <TableCell>
309
+ <span className="text-body-medium">
310
+ {property.propertyType ?? "—"}
311
+ </span>
312
+ </TableCell>
313
+ <TableCell>
314
+ <span className="text-body-medium">
315
+ {property.estimateValue
316
+ ? formatCurrency(property.estimateValue)
317
+ : "—"}
318
+ </span>
319
+ </TableCell>
320
+ <TableCell>
321
+ {isManual(property.id) && (
322
+ <Button
323
+ variant="ghost"
324
+ size="icon-sm"
325
+ aria-label="Remove property"
326
+ onClick={() => handleRemoveManual(property.id)}
327
+ >
328
+ <Trash2 className="size-4" />
329
+ </Button>
330
+ )}
331
+ </TableCell>
332
+ </TableRow>
333
+ ))}
334
+ </TableBody>
335
+ </Table>
336
+ )}
337
+ </div>
338
+ </div>
339
+
340
+ <DialogFooter>
341
+ <Button variant="ghost" onClick={onClose}>
342
+ Cancel
343
+ </Button>
344
+ <Button
345
+ onClick={handleSubmit}
346
+ disabled={isSubmitDisabled}
347
+ loading={isLoading}
348
+ >
349
+ Generate
350
+ </Button>
351
+ </DialogFooter>
352
+ </DialogContent>
353
+ </Dialog>
354
+ );
355
+ }